From 223fc437c495b2c3ee6f265e2ac6120ca13fa884 Mon Sep 17 00:00:00 2001 From: Hamza Israr <71447999+HamzaIsrar12@users.noreply.github.com> Date: Mon, 6 May 2024 16:38:06 +0500 Subject: [PATCH 01/38] fix: Ensure cookies authentication prior to webview loading (#312) Ensure cookies' expiry time is verified before loading a webview. Additionally, addressed a race condition within the `clearWebViewCookie` method. This race condition caused the premature reset of `authSessionCookieExpiration` to -1 due to delays in the callback execution. Fixes: LEARNER-9891 --- .../org/openedx/core/extension/ViewExt.kt | 15 ++++++++ .../openedx/core/system/AppCookieManager.kt | 14 +------ .../unit/html/HtmlUnitFragment.kt | 38 +++++++++++++++---- .../presentation/program/ProgramFragment.kt | 22 +++++++---- .../presentation/program/ProgramViewModel.kt | 6 +-- 5 files changed, 65 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/openedx/core/extension/ViewExt.kt b/core/src/main/java/org/openedx/core/extension/ViewExt.kt index ff2e95d47..9146a3159 100644 --- a/core/src/main/java/org/openedx/core/extension/ViewExt.kt +++ b/core/src/main/java/org/openedx/core/extension/ViewExt.kt @@ -6,8 +6,12 @@ import android.graphics.Rect import android.util.DisplayMetrics import android.view.View import android.view.ViewGroup +import android.webkit.WebView import android.widget.Toast import androidx.fragment.app.DialogFragment +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.openedx.core.system.AppCookieManager fun Context.dpToPixel(dp: Int): Float { return dp * (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT) @@ -46,3 +50,14 @@ fun DialogFragment.setWidthPercent(percentage: Int) { fun Context.toastMessage(message: String) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show() } + +fun WebView.loadUrl(url: String, scope: CoroutineScope, cookieManager: AppCookieManager) { + if (cookieManager.isSessionCookieMissingOrExpired()) { + scope.launch { + cookieManager.tryToRefreshSessionCookie() + loadUrl(url) + } + } else { + loadUrl(url) + } +} diff --git a/core/src/main/java/org/openedx/core/system/AppCookieManager.kt b/core/src/main/java/org/openedx/core/system/AppCookieManager.kt index f09e16362..7df19c627 100644 --- a/core/src/main/java/org/openedx/core/system/AppCookieManager.kt +++ b/core/src/main/java/org/openedx/core/system/AppCookieManager.kt @@ -11,8 +11,6 @@ import java.util.concurrent.TimeUnit class AppCookieManager(private val config: Config, private val api: CookiesApi) { companion object { - private const val REV_934_COOKIE = - "REV_934=mobile; expires=Tue, 31 Dec 2021 12:00:20 GMT; domain=.edx.org;" private val FRESHNESS_INTERVAL = TimeUnit.HOURS.toMillis(1) } @@ -34,19 +32,11 @@ class AppCookieManager(private val config: Config, private val api: CookiesApi) } fun clearWebViewCookie() { - CookieManager.getInstance().removeAllCookies { result -> - if (result) { - authSessionCookieExpiration = -1 - } - } + CookieManager.getInstance().removeAllCookies(null) + authSessionCookieExpiration = -1 } fun isSessionCookieMissingOrExpired(): Boolean { return authSessionCookieExpiration < System.currentTimeMillis() } - - fun setMobileCookie() { - CookieManager.getInstance().setCookie(config.getApiHostURL(), REV_934_COOKIE) - } - } diff --git a/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt b/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt index a74b9d5ee..3a49e0e4b 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt @@ -9,13 +9,30 @@ import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup -import android.webkit.* +import android.webkit.JavascriptInterface +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse +import android.webkit.WebView +import android.webkit.WebViewClient import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.* -import androidx.compose.runtime.* +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -33,10 +50,15 @@ import androidx.fragment.app.Fragment import kotlinx.coroutines.launch import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.core.extension.isEmailValid +import org.openedx.core.extension.loadUrl import org.openedx.core.system.AppCookieManager -import org.openedx.core.ui.* +import org.openedx.core.ui.ConnectionErrorView +import org.openedx.core.ui.WindowSize +import org.openedx.core.ui.rememberWindowSize +import org.openedx.core.ui.roundBorderWithoutBottom import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.windowSizeValue import org.openedx.core.utils.EmailUtil class HtmlUnitFragment : Fragment() { @@ -268,13 +290,15 @@ private fun HTMLContentView( } isVerticalScrollBarEnabled = false isHorizontalScrollBarEnabled = false - loadUrl(url) + + loadUrl(url, coroutineScope, cookieManager) } }, update = { webView -> if (!isLoading && injectJSList.isNotEmpty()) { injectJSList.forEach { webView.evaluateJavascript(it, null) } } - }) + } + ) } diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt index 4e97efe18..ee3e04a3b 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt @@ -23,6 +23,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -41,10 +42,14 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.zIndex import androidx.core.os.bundleOf import androidx.fragment.app.Fragment +import kotlinx.coroutines.launch +import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.ext.android.viewModel +import org.openedx.core.extension.loadUrl import org.openedx.core.extension.toastMessage import org.openedx.core.presentation.dialog.alert.ActionDialogFragment import org.openedx.core.presentation.dialog.alert.InfoDialogFragment +import org.openedx.core.system.AppCookieManager import org.openedx.core.ui.ConnectionErrorView import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.Toolbar @@ -119,6 +124,7 @@ class ProgramFragment(private val myPrograms: Boolean = false) : Fragment() { windowSize = windowSize, uiState = uiState, contentUrl = getInitialUrl(), + cookieManager = viewModel.cookieManager, canShowBackBtn = arguments?.getString(ARG_PATH_ID, "") ?.isNotEmpty() == true, uriScheme = viewModel.uriScheme, @@ -182,15 +188,11 @@ class ProgramFragment(private val myPrograms: Boolean = false) : Fragment() { onSettingsClick = { viewModel.navigateToSettings(requireActivity().supportFragmentManager) }, - refreshSessionCookie = { - viewModel.refreshCookie() - }, ) } } } - private fun getInitialUrl(): String { return arguments?.let { args -> val pathId = args.getString(ARG_PATH_ID) ?: "" @@ -219,6 +221,7 @@ private fun ProgramInfoScreen( windowSize: WindowSize, uiState: ProgramUIState?, contentUrl: String, + cookieManager: AppCookieManager, uriScheme: String, canShowBackBtn: Boolean, hasInternetConnection: Boolean, @@ -227,10 +230,10 @@ private fun ProgramInfoScreen( onSettingsClick: () -> Unit, onBackClick: () -> Unit, onUriClick: (String, WebViewLink.Authority) -> Unit, - refreshSessionCookie: () -> Unit = {}, ) { val scaffoldState = rememberScaffoldState() val configuration = LocalConfiguration.current + val coroutineScope = rememberCoroutineScope() val isLoading = uiState is ProgramUIState.Loading when (uiState) { @@ -290,7 +293,11 @@ private fun ProgramInfoScreen( uriScheme = uriScheme, isAllLinksExternal = true, onWebPageLoaded = onWebPageLoaded, - refreshSessionCookie = refreshSessionCookie, + refreshSessionCookie = { + coroutineScope.launch { + cookieManager.tryToRefreshSessionCookie() + } + }, onUriClick = onUriClick, ) @@ -301,7 +308,7 @@ private fun ProgramInfoScreen( webView }, update = { - webView.loadUrl(contentUrl) + webView.loadUrl(contentUrl, coroutineScope, cookieManager) } ) } else { @@ -339,6 +346,7 @@ fun MyProgramsPreview() { windowSize = WindowSize(WindowType.Compact, WindowType.Compact), uiState = ProgramUIState.Loading, contentUrl = "https://www.example.com/", + cookieManager = koinViewModel().cookieManager, uriScheme = "", canShowBackBtn = false, hasInternetConnection = false, diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramViewModel.kt b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramViewModel.kt index 68bbdc6be..1bed6d2cd 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramViewModel.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramViewModel.kt @@ -34,6 +34,8 @@ class ProgramViewModel( val programConfig get() = config.getProgramConfig().webViewConfig + val cookieManager get() = edxCookieManager + val hasInternetConnection: Boolean get() = networkConnection.isOnline() private val _uiState = MutableSharedFlow( @@ -104,8 +106,4 @@ class ProgramViewModel( fun navigateToSettings(fragmentManager: FragmentManager) { router.navigateToSettings(fragmentManager) } - - fun refreshCookie() { - viewModelScope.launch { edxCookieManager.tryToRefreshSessionCookie() } - } } From 498f0ef64cfeb8b88c62817f465d4dea19662ef4 Mon Sep 17 00:00:00 2001 From: droid Date: Mon, 15 Apr 2024 16:54:02 +0200 Subject: [PATCH 02/38] fix: crash when restoring the app after a long period of inactivity --- .../java/org/openedx/app/di/ScreenModule.kt | 25 +++- .../core/system/notifier/CourseDataReady.kt | 5 - .../core/system/notifier/CourseNotifier.kt | 1 - .../data/repository/CourseRepository.kt | 53 +++---- .../domain/interactor/CourseInteractor.kt | 22 +-- .../container/CourseContainerFragment.kt | 33 +++-- .../container/CourseContainerViewModel.kt | 11 +- .../dates/CourseDatesViewModel.kt | 31 ++-- .../outline/CourseOutlineViewModel.kt | 10 +- .../section/CourseSectionViewModel.kt | 4 +- .../container/CourseUnitContainerFragment.kt | 3 +- .../container/CourseUnitContainerViewModel.kt | 35 +++-- .../videos/CourseVideoViewModel.kt | 15 +- .../container/CourseContainerViewModelTest.kt | 62 +++++--- .../dates/CourseDatesViewModelTest.kt | 19 ++- .../outline/CourseOutlineViewModelTest.kt | 39 ++--- .../section/CourseSectionViewModelTest.kt | 31 ++-- .../CourseUnitContainerViewModelTest.kt | 133 +++++++++--------- .../videos/CourseVideoViewModelTest.kt | 26 ++-- .../topics/DiscussionTopicsScreen.kt | 2 +- .../topics/DiscussionTopicsViewModel.kt | 20 +-- .../topics/DiscussionTopicsViewModelTest.kt | 15 +- 22 files changed, 319 insertions(+), 276 deletions(-) delete mode 100644 core/src/main/java/org/openedx/core/system/notifier/CourseDataReady.kt diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 4efd1a19e..c9c395a01 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -148,10 +148,23 @@ val screenModule = module { viewModel { (qualityType: String) -> VideoQualityViewModel(qualityType, get(), get(), get()) } viewModel { DeleteProfileViewModel(get(), get(), get(), get(), get()) } viewModel { (username: String) -> AnothersProfileViewModel(get(), get(), username) } - viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) } + viewModel { + SettingsViewModel( + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get() + ) + } viewModel { ManageAccountViewModel(get(), get(), get(), get(), get()) } - single { CourseRepository(get(), get(), get(), get()) } + single { CourseRepository(get(), get(), get(), get(), get()) } factory { CourseInteractor(get()) } viewModel { (pathId: String, infoType: String) -> CourseInfoViewModel( @@ -279,8 +292,10 @@ val screenModule = module { get(), ) } - viewModel { (enrollmentMode: String) -> + viewModel { (courseId: String, courseTitle: String, enrollmentMode: String) -> CourseDatesViewModel( + courseId, + courseTitle, enrollmentMode, get(), get(), @@ -305,8 +320,10 @@ val screenModule = module { single { DiscussionRepository(get(), get(), get()) } factory { DiscussionInteractor(get()) } - viewModel { + viewModel { (courseId: String, courseTitle: String) -> DiscussionTopicsViewModel( + courseId, + courseTitle, get(), get(), get(), diff --git a/core/src/main/java/org/openedx/core/system/notifier/CourseDataReady.kt b/core/src/main/java/org/openedx/core/system/notifier/CourseDataReady.kt deleted file mode 100644 index 0ad123d17..000000000 --- a/core/src/main/java/org/openedx/core/system/notifier/CourseDataReady.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.openedx.core.system.notifier - -import org.openedx.core.domain.model.CourseStructure - -data class CourseDataReady(val courseStructure: CourseStructure) : CourseEvent diff --git a/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt b/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt index 63660b4de..f4908bdef 100644 --- a/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt +++ b/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt @@ -18,6 +18,5 @@ class CourseNotifier { suspend fun send(event: CalendarSyncEvent) = channel.emit(event) suspend fun send(event: CourseDatesShifted) = channel.emit(event) suspend fun send(event: CourseLoading) = channel.emit(event) - suspend fun send(event: CourseDataReady) = channel.emit(event) suspend fun send(event: CourseRefresh) = channel.emit(event) } 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 17dc6a240..c32397a48 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 @@ -5,9 +5,11 @@ import org.openedx.core.ApiConstants import org.openedx.core.data.api.CourseApi import org.openedx.core.data.model.BlocksCompletionBody import org.openedx.core.data.storage.CorePreferences -import org.openedx.core.domain.model.* +import org.openedx.core.domain.model.CourseComponentStatus +import org.openedx.core.domain.model.CourseStructure import org.openedx.core.exception.NoCachedDataException import org.openedx.core.module.db.DownloadDao +import org.openedx.core.system.connection.NetworkConnection import org.openedx.course.data.storage.CourseDao class CourseRepository( @@ -15,8 +17,9 @@ class CourseRepository( private val courseDao: CourseDao, private val downloadDao: DownloadDao, private val preferencesManager: CorePreferences, + private val networkConnection: NetworkConnection, ) { - private var courseStructure: CourseStructure? = null + private var courseStructure = mutableMapOf() suspend fun removeDownloadModel(id: String) { downloadDao.removeDownloadModel(id) @@ -26,35 +29,33 @@ class CourseRepository( list.map { it.mapToDomain() } } - suspend fun preloadCourseStructure(courseId: String) { - val response = api.getCourseStructure( - "stale-if-error=0", - "v3", - preferencesManager.user?.username, - courseId - ) - courseDao.insertCourseStructureEntity(response.mapToRoomEntity()) - courseStructure = null - courseStructure = response.mapToDomain() + fun hasCourses(courseId: String): Boolean { + return courseStructure[courseId] != null } - suspend fun preloadCourseStructureFromCache(courseId: String) { - val cachedCourseStructure = courseDao.getCourseStructureById(courseId) - courseStructure = null - if (cachedCourseStructure != null) { - courseStructure = cachedCourseStructure.mapToDomain() - } else { - throw NoCachedDataException() - } - } + suspend fun getCourseStructure(courseId: String, isNeedRefresh: Boolean): CourseStructure { + if (!isNeedRefresh) courseStructure[courseId]?.let { return it } + + if (networkConnection.isOnline()) { + val response = api.getCourseStructure( + "stale-if-error=0", + "v3", + preferencesManager.user?.username, + courseId + ) + courseDao.insertCourseStructureEntity(response.mapToRoomEntity()) + courseStructure[courseId] = response.mapToDomain() - @Throws(IllegalStateException::class) - fun getCourseStructureFromCache(): CourseStructure { - if (courseStructure != null) { - return courseStructure!! } else { - throw IllegalStateException("Course structure is empty") + val cachedCourseStructure = courseDao.getCourseStructureById(courseId) + if (cachedCourseStructure != null) { + courseStructure[courseId] = cachedCourseStructure.mapToDomain() + } else { + throw NoCachedDataException() + } } + + return courseStructure[courseId]!! } suspend fun getCourseStatus(courseId: String): CourseComponentStatus { 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 6c8bd1009..5bc859120 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 @@ -9,18 +9,18 @@ class CourseInteractor( private val repository: CourseRepository ) { - suspend fun preloadCourseStructure(courseId: String) = - repository.preloadCourseStructure(courseId) - - suspend fun preloadCourseStructureFromCache(courseId: String) = - repository.preloadCourseStructureFromCache(courseId) - - @Throws(IllegalStateException::class) - fun getCourseStructureFromCache() = repository.getCourseStructureFromCache() + suspend fun getCourseStructure( + courseId: String, + isNeedRefresh: Boolean = false + ): CourseStructure { + return repository.getCourseStructure(courseId, isNeedRefresh) + } - @Throws(IllegalStateException::class) - fun getCourseStructureForVideos(): CourseStructure { - val courseStructure = repository.getCourseStructureFromCache() + suspend fun getCourseStructureForVideos( + courseId: String, + isNeedRefresh: Boolean = false + ): CourseStructure { + val courseStructure = repository.getCourseStructure(courseId, isNeedRefresh) val blocks = courseStructure.blockData val videoBlocks = blocks.filter { it.type == BlockType.VIDEO } val resultBlocks = ArrayList() 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 c44733948..669b1f661 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 @@ -30,6 +30,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState 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.rememberCoroutineScope @@ -294,6 +295,8 @@ fun CourseDashboard( val refreshing by viewModel.refreshing.collectAsState(true) val courseImage by viewModel.courseImage.collectAsState() val uiMessage by viewModel.uiMessage.collectAsState(null) + val dataReady = viewModel.dataReady.observeAsState() + val pagerState = rememberPagerState(pageCount = { CourseContainerTab.entries.size }) val tabState = rememberLazyListState() val snackState = remember { SnackbarHostState() } @@ -351,15 +354,17 @@ fun CourseDashboard( fragmentManager.popBackStack() }, bodyContent = { - DashboardPager( - windowSize = windowSize, - viewModel = viewModel, - pagerState = pagerState, - isNavigationEnabled = isNavigationEnabled, - isResumed = isResumed, - fragmentManager = fragmentManager, - bundle = bundle - ) + if (dataReady.value == true) { + DashboardPager( + windowSize = windowSize, + viewModel = viewModel, + pagerState = pagerState, + isNavigationEnabled = isNavigationEnabled, + isResumed = isResumed, + fragmentManager = fragmentManager, + bundle = bundle + ) + } } ) PullRefreshIndicator( @@ -462,6 +467,8 @@ fun DashboardPager( courseDatesViewModel = koinViewModel( parameters = { parametersOf( + bundle.getString(CourseContainerFragment.ARG_COURSE_ID, ""), + bundle.getString(CourseContainerFragment.ARG_TITLE, ""), bundle.getString(CourseContainerFragment.ARG_ENROLLMENT_MODE, "") ) } @@ -478,6 +485,14 @@ fun DashboardPager( CourseContainerTab.DISCUSSIONS -> { DiscussionTopicsScreen( + discussionTopicsViewModel = koinViewModel( + parameters = { + parametersOf( + bundle.getString(CourseContainerFragment.ARG_COURSE_ID, ""), + bundle.getString(CourseContainerFragment.ARG_TITLE, ""), + ) + } + ), windowSize = windowSize, fragmentManager = fragmentManager ) 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 c61d7e165..8562289af 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 @@ -31,7 +31,6 @@ import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CalendarSyncEvent.CheckCalendarSyncEvent import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent import org.openedx.core.system.notifier.CourseCompletionSet -import org.openedx.core.system.notifier.CourseDataReady import org.openedx.core.system.notifier.CourseDatesShifted import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier @@ -169,12 +168,7 @@ class CourseContainerViewModel( _showProgress.value = true viewModelScope.launch { try { - if (networkConnection.isOnline()) { - interactor.preloadCourseStructure(courseId) - } else { - interactor.preloadCourseStructureFromCache(courseId) - } - val courseStructure = interactor.getCourseStructureFromCache() + val courseStructure = interactor.getCourseStructure(courseId) courseName = courseStructure.name _organization = courseStructure.org _isSelfPaced = courseStructure.isSelfPaced @@ -183,7 +177,6 @@ class CourseContainerViewModel( val isReady = start < Date() if (isReady) { _isNavigationEnabled.value = true - courseNotifier.send(CourseDataReady(courseStructure)) } isReady } @@ -248,7 +241,7 @@ class CourseContainerViewModel( fun updateData() { viewModelScope.launch { try { - interactor.preloadCourseStructure(courseId) + interactor.getCourseStructure(courseId, isNeedRefresh = true) } catch (e: Exception) { if (e.isInternetError()) { _errorMessage.value = 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 79f866ba7..e5ce08ed7 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 @@ -19,6 +19,7 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.CourseBannerType import org.openedx.core.domain.model.CourseDateBlock +import org.openedx.core.domain.model.CourseStructure import org.openedx.core.extension.getSequentialBlocks import org.openedx.core.extension.getVerticalBlocks import org.openedx.core.extension.isInternetError @@ -26,7 +27,6 @@ import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CalendarSyncEvent.CheckCalendarSyncEvent import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent -import org.openedx.core.system.notifier.CourseDataReady import org.openedx.core.system.notifier.CourseDatesShifted import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier @@ -41,6 +41,8 @@ import org.openedx.course.presentation.calendarsync.CalendarSyncUIState import org.openedx.core.R as CoreR class CourseDatesViewModel( + val courseId: String, + courseTitle: String, private val enrollmentMode: String, private val courseNotifier: CourseNotifier, private val interactor: CourseInteractor, @@ -51,8 +53,6 @@ class CourseDatesViewModel( private val config: Config, ) : BaseViewModel() { - var courseId = "" - var courseName = "" var isSelfPaced = true private val _uiState = MutableLiveData(DatesUIState.Loading) @@ -66,7 +66,7 @@ class CourseDatesViewModel( private val _calendarSyncUIState = MutableStateFlow( CalendarSyncUIState( isCalendarSyncEnabled = isCalendarSyncEnabled(), - calendarTitle = calendarManager.getCourseCalendarTitle(courseName), + calendarTitle = calendarManager.getCourseCalendarTitle(courseTitle), isSynced = false, ) ) @@ -74,6 +74,7 @@ class CourseDatesViewModel( _calendarSyncUIState.asStateFlow() private var courseBannerType: CourseBannerType = CourseBannerType.BLANK + private var courseStructure: CourseStructure? = null val isCourseExpandableSectionsEnabled get() = config.isCourseNestedListEnabled() @@ -90,22 +91,19 @@ class CourseDatesViewModel( loadingCourseDatesInternal() } } - - is CourseDataReady -> { - courseId = event.courseStructure.id - courseName = event.courseStructure.name - isSelfPaced = event.courseStructure.isSelfPaced - loadingCourseDatesInternal() - updateAndFetchCalendarSyncState() - } } } } + + loadingCourseDatesInternal() + updateAndFetchCalendarSyncState() } private fun loadingCourseDatesInternal() { viewModelScope.launch { try { + courseStructure = interactor.getCourseStructure(courseId = courseId) + isSelfPaced = courseStructure?.isSelfPaced ?: false val datesResponse = interactor.getCourseDates(courseId = courseId) if (datesResponse.datesSection.isEmpty()) { _uiState.value = DatesUIState.Empty @@ -146,8 +144,8 @@ class CourseDatesViewModel( fun getVerticalBlock(blockId: String): Block? { return try { - val courseStructure = interactor.getCourseStructureFromCache() - courseStructure.blockData.getVerticalBlocks().find { it.descendants.contains(blockId) } + courseStructure?.blockData?.getVerticalBlocks() + ?.find { it.descendants.contains(blockId) } } catch (e: Exception) { null } @@ -155,9 +153,8 @@ class CourseDatesViewModel( fun getSequentialBlock(blockId: String): Block? { return try { - val courseStructure = interactor.getCourseStructureFromCache() - courseStructure.blockData.getSequentialBlocks() - .find { it.descendants.contains(blockId) } + courseStructure?.blockData?.getSequentialBlocks() + ?.find { it.descendants.contains(blockId) } } catch (e: Exception) { null } 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 569498ab6..7a6e08b58 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 @@ -28,7 +28,6 @@ import org.openedx.core.presentation.CoreAnalytics import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent -import org.openedx.core.system.notifier.CourseDataReady import org.openedx.core.system.notifier.CourseDatesShifted import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier @@ -84,15 +83,12 @@ class CourseOutlineViewModel( init { viewModelScope.launch { courseNotifier.notifier.collect { event -> - when(event) { + when (event) { is CourseStructureUpdated -> { if (event.courseId == courseId) { updateCourseData() } } - is CourseDataReady -> { - getCourseData() - } } } } @@ -113,6 +109,8 @@ class CourseOutlineViewModel( } } } + + getCourseData() } override fun saveDownloadModels(folder: String, id: String) { @@ -166,7 +164,7 @@ class CourseOutlineViewModel( private fun getCourseDataInternal() { viewModelScope.launch { try { - var courseStructure = interactor.getCourseStructureFromCache() + var courseStructure = interactor.getCourseStructure(courseId) val blocks = courseStructure.blockData val courseStatus = if (networkConnection.isOnline()) { diff --git a/course/src/main/java/org/openedx/course/presentation/section/CourseSectionViewModel.kt b/course/src/main/java/org/openedx/course/presentation/section/CourseSectionViewModel.kt index 97f241650..33870c69c 100644 --- a/course/src/main/java/org/openedx/course/presentation/section/CourseSectionViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/section/CourseSectionViewModel.kt @@ -89,8 +89,8 @@ class CourseSectionViewModel( viewModelScope.launch { try { val courseStructure = when (mode) { - CourseViewMode.FULL -> interactor.getCourseStructureFromCache() - CourseViewMode.VIDEOS -> interactor.getCourseStructureForVideos() + CourseViewMode.FULL -> interactor.getCourseStructure(courseId) + CourseViewMode.VIDEOS -> interactor.getCourseStructureForVideos(courseId) } val blocks = courseStructure.blockData setBlocks(blocks) diff --git a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerFragment.kt b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerFragment.kt index fc7c9213f..1bc26e1a4 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerFragment.kt @@ -134,8 +134,7 @@ class CourseUnitContainerFragment : Fragment(R.layout.fragment_course_unit_conta super.onCreate(savedInstanceState) lifecycle.addObserver(viewModel) componentId = requireArguments().getString(ARG_COMPONENT_ID, "") - viewModel.loadBlocks(requireArguments().serializable(ARG_MODE)!!) - viewModel.setupCurrentIndex(componentId) + viewModel.loadBlocks(requireArguments().serializable(ARG_MODE)!!, componentId) viewModel.courseUnitContainerShowedEvent() } diff --git a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt index 323adb7cb..f479f08c0 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt @@ -76,23 +76,28 @@ class CourseUnitContainerViewModel( var hasNextBlock = false private var currentMode: CourseViewMode? = null + private var currentComponentId = "" private var courseName = "" private val _descendantsBlocks = MutableStateFlow>(listOf()) val descendantsBlocks = _descendantsBlocks.asStateFlow() - fun loadBlocks(mode: CourseViewMode) { + fun loadBlocks(mode: CourseViewMode, componentId: String = "") { currentMode = mode - try { - val courseStructure = when (mode) { - CourseViewMode.FULL -> interactor.getCourseStructureFromCache() - CourseViewMode.VIDEOS -> interactor.getCourseStructureForVideos() + viewModelScope.launch { + try { + val courseStructure = when (mode) { + CourseViewMode.FULL -> interactor.getCourseStructure(courseId) + CourseViewMode.VIDEOS -> interactor.getCourseStructureForVideos(courseId) + } + val blocks = courseStructure.blockData + courseName = courseStructure.name + this@CourseUnitContainerViewModel.blocks.clearAndAddAll(blocks) + + setupCurrentIndex(componentId) + } catch (e: Exception) { + e.printStackTrace() } - val blocks = courseStructure.blockData - courseName = courseStructure.name - this.blocks.clearAndAddAll(blocks) - } catch (e: Exception) { - //ignore e.printStackTrace() } } @@ -104,7 +109,7 @@ class CourseUnitContainerViewModel( if (event is CourseStructureUpdated) { if (event.courseId != courseId) return@collect - currentMode?.let { loadBlocks(it) } + currentMode?.let { loadBlocks(it, currentComponentId) } val blockId = blocks[currentVerticalIndex].id _subSectionUnitBlocks.value = getSubSectionUnitBlocks(blocks, getSubSectionId(blockId)) @@ -113,10 +118,10 @@ class CourseUnitContainerViewModel( } } - fun setupCurrentIndex(componentId: String = "") { - if (currentSectionIndex != -1) { - return - } + private fun setupCurrentIndex(componentId: String = "") { + if (currentSectionIndex != -1) return + currentComponentId = componentId + blocks.forEachIndexed { index, block -> if (block.id == unitId) { currentVerticalIndex = index diff --git a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt index dc88105a8..f5e9be934 100644 --- a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt @@ -20,7 +20,6 @@ import org.openedx.core.module.download.BaseDownloadViewModel import org.openedx.core.presentation.CoreAnalytics import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.CourseDataReady import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseStructureUpdated @@ -75,13 +74,9 @@ class CourseVideoViewModel( when (event) { is CourseStructureUpdated -> { if (event.courseId == courseId) { - updateVideos() + getVideos() } } - - is CourseDataReady -> { - getVideos() - } } } } @@ -114,6 +109,8 @@ class CourseVideoViewModel( } _videoSettings.value = preferencesManager.videoSettings + + getVideos() } override fun saveDownloadModels(folder: String, id: String) { @@ -141,13 +138,9 @@ class CourseVideoViewModel( super.saveAllDownloadModels(folder) } - private fun updateVideos() { - getVideos() - } - fun getVideos() { viewModelScope.launch { - var courseStructure = interactor.getCourseStructureForVideos() + var courseStructure = interactor.getCourseStructureForVideos(courseId) val blocks = courseStructure.blockData if (blocks.isEmpty()) { _uiState.value = CourseVideosUIState.Empty( diff --git a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt index 63dce6272..1b2cb6cca 100644 --- a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt @@ -25,6 +25,8 @@ import org.junit.rules.TestRule import org.openedx.core.ImageProcessor import org.openedx.core.R import org.openedx.core.config.Config +import org.openedx.core.data.api.CourseApi +import org.openedx.core.data.model.CourseStructureModel import org.openedx.core.data.model.User import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.AppConfig @@ -64,6 +66,7 @@ class CourseContainerViewModelTest { private val mockBitmap = mockk() private val imageProcessor = mockk() private val courseRouter = mockk() + private val courseApi = mockk() private val openEdx = "OpenEdx" private val calendarTitle = "OpenEdx - Abc" @@ -108,6 +111,23 @@ class CourseContainerViewModelTest { isSelfPaced = false ) + private val courseStructureModel = CourseStructureModel( + root = "", + blockData = mapOf(), + id = "id", + name = "Course name", + number = "", + org = "Org", + start = "", + startDisplay = "", + startType = "", + end = null, + coursewareAccess = null, + media = null, + certificate = null, + isSelfPaced = false + ) + @Before fun setUp() { Dispatchers.setMain(dispatcher) @@ -129,7 +149,7 @@ class CourseContainerViewModelTest { } @Test - fun `preloadCourseStructure internet connection exception`() = runTest { + fun `getCourseStructure internet connection exception`() = runTest { val viewModel = CourseContainerViewModel( "", "", @@ -147,12 +167,12 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns true - coEvery { interactor.preloadCourseStructure(any()) } throws UnknownHostException() + coEvery { interactor.getCourseStructure(any()) } throws UnknownHostException() every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() - coVerify(exactly = 1) { interactor.preloadCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any()) } verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } val message = viewModel.errorMessage.value @@ -162,7 +182,7 @@ class CourseContainerViewModelTest { } @Test - fun `preloadCourseStructure unknown exception`() = runTest { + fun `getCourseStructure unknown exception`() = runTest { val viewModel = CourseContainerViewModel( "", "", @@ -180,12 +200,12 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns true - coEvery { interactor.preloadCourseStructure(any()) } throws Exception() + coEvery { interactor.getCourseStructure(any()) } throws Exception() every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() - coVerify(exactly = 1) { interactor.preloadCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any()) } verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } val message = viewModel.errorMessage.value @@ -195,7 +215,7 @@ class CourseContainerViewModelTest { } @Test - fun `preloadCourseStructure success with internet`() = runTest { + fun `getCourseStructure success with internet`() = runTest { val viewModel = CourseContainerViewModel( "", "", @@ -213,13 +233,12 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns true - coEvery { interactor.preloadCourseStructure(any()) } returns Unit - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() - coVerify(exactly = 1) { interactor.preloadCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any()) } verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } assert(viewModel.errorMessage.value == null) @@ -228,7 +247,7 @@ class CourseContainerViewModelTest { } @Test - fun `preloadCourseStructure success without internet`() = runTest { + fun `getCourseStructure success without internet`() = runTest { val viewModel = CourseContainerViewModel( "", "", @@ -246,14 +265,15 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns false - coEvery { interactor.preloadCourseStructureFromCache(any()) } returns Unit - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { analytics.logEvent(any(), any()) } returns Unit + coEvery { + courseApi.getCourseStructure(any(), any(), any(), any()) + } returns courseStructureModel viewModel.preloadCourseStructure() advanceUntilIdle() - coVerify(exactly = 0) { interactor.preloadCourseStructure(any()) } - coVerify(exactly = 1) { interactor.preloadCourseStructureFromCache(any()) } + coVerify(exactly = 0) { courseApi.getCourseStructure(any(), any(), any(), any()) } verify(exactly = 1) { analytics.logEvent(any(), any()) } assert(viewModel.errorMessage.value == null) @@ -279,12 +299,12 @@ class CourseContainerViewModelTest { imageProcessor, courseRouter ) - coEvery { interactor.preloadCourseStructure(any()) } throws UnknownHostException() + coEvery { interactor.getCourseStructure(any(), true) } throws UnknownHostException() coEvery { notifier.send(CourseStructureUpdated("")) } returns Unit viewModel.updateData() advanceUntilIdle() - coVerify(exactly = 1) { interactor.preloadCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any(), true) } val message = viewModel.errorMessage.value assertEquals(noInternet, message) @@ -309,12 +329,12 @@ class CourseContainerViewModelTest { imageProcessor, courseRouter ) - coEvery { interactor.preloadCourseStructure(any()) } throws Exception() + coEvery { interactor.getCourseStructure(any(), true) } throws Exception() coEvery { notifier.send(CourseStructureUpdated("")) } returns Unit viewModel.updateData() advanceUntilIdle() - coVerify(exactly = 1) { interactor.preloadCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any(), true) } val message = viewModel.errorMessage.value assertEquals(somethingWrong, message) @@ -339,12 +359,12 @@ class CourseContainerViewModelTest { imageProcessor, courseRouter ) - coEvery { interactor.preloadCourseStructure(any()) } returns Unit + coEvery { interactor.getCourseStructure(any(), true) } returns courseStructure coEvery { notifier.send(CourseStructureUpdated("")) } returns Unit viewModel.updateData() advanceUntilIdle() - coVerify(exactly = 1) { interactor.preloadCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any(), true) } assert(viewModel.errorMessage.value == null) assert(!viewModel.refreshing.value) diff --git a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt index 40a2d41c0..13e78fe91 100644 --- a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt @@ -39,7 +39,6 @@ import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.DatesSection import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent -import org.openedx.core.system.notifier.CourseDataReady import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.course.domain.interactor.CourseInteractor @@ -143,15 +142,15 @@ class CourseDatesViewModelTest { every { resourceManager.getString(id = R.string.platform_name) } returns openEdx every { resourceManager.getString(R.string.core_error_no_connection) } returns noInternet every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { corePreferences.user } returns user every { corePreferences.appConfig } returns appConfig - every { notifier.notifier } returns flowOf(CourseDataReady(courseStructure)) + every { notifier.notifier } returns flowOf(CourseLoading(false)) every { calendarManager.getCourseCalendarTitle(any()) } returns calendarTitle every { calendarManager.isCalendarExists(any()) } returns true coEvery { notifier.send(any()) } returns Unit coEvery { notifier.send(any()) } returns Unit - coEvery { notifier.send(any()) } returns Unit + coEvery { notifier.send(any()) } returns Unit } @After @@ -162,6 +161,8 @@ class CourseDatesViewModelTest { @Test fun `getCourseDates no internet connection exception`() = runTest(UnconfinedTestDispatcher()) { val viewModel = CourseDatesViewModel( + "id", + "", "", notifier, interactor, @@ -179,15 +180,17 @@ class CourseDatesViewModelTest { } advanceUntilIdle() - coVerify(exactly = 1) { interactor.getCourseDates(any()) } + coVerify(exactly = 1) { interactor.getCourseDates(any()) } Assert.assertEquals(noInternet, message.await()?.message) assert(viewModel.uiState.value is DatesUIState.Loading) } @Test - fun `getCourseDates unknown exception`() = runTest(UnconfinedTestDispatcher()) { + fun `getCourseDates unknown exception`() = runTest(UnconfinedTestDispatcher()) { val viewModel = CourseDatesViewModel( + "id", + "", "", notifier, interactor, @@ -214,6 +217,8 @@ class CourseDatesViewModelTest { @Test fun `getCourseDates success with internet`() = runTest(UnconfinedTestDispatcher()) { val viewModel = CourseDatesViewModel( + "id", + "", "", notifier, interactor, @@ -240,6 +245,8 @@ class CourseDatesViewModelTest { @Test fun `getCourseDates success with EmptyList`() = runTest(UnconfinedTestDispatcher()) { val viewModel = CourseDatesViewModel( + "id", + "", "", notifier, interactor, 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 098960a2a..c2b2cff57 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 @@ -218,7 +218,7 @@ class CourseOutlineViewModelTest { @Test fun `getCourseDataInternal no internet connection exception`() = runTest(UnconfinedTestDispatcher()) { - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { networkConnection.isOnline() } returns true every { downloadDao.readAllData() } returns flow { emit(emptyList()) } coEvery { interactor.getCourseStatus(any()) } throws UnknownHostException() @@ -244,8 +244,8 @@ class CourseOutlineViewModelTest { viewModel.getCourseData() advanceUntilIdle() - verify(exactly = 1) { interactor.getCourseStructureFromCache() } - coVerify(exactly = 1) { interactor.getCourseStatus(any()) } + coVerify(exactly = 2) { interactor.getCourseStructure(any()) } + coVerify(exactly = 2) { interactor.getCourseStatus(any()) } assertEquals(noInternet, message.await()?.message) assert(viewModel.uiState.value is CourseOutlineUIState.Loading) @@ -253,7 +253,7 @@ class CourseOutlineViewModelTest { @Test fun `getCourseDataInternal unknown exception`() = runTest(UnconfinedTestDispatcher()) { - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { networkConnection.isOnline() } returns true every { downloadDao.readAllData() } returns flow { emit(emptyList()) } coEvery { interactor.getCourseStatus(any()) } throws Exception() @@ -278,8 +278,8 @@ class CourseOutlineViewModelTest { viewModel.getCourseData() advanceUntilIdle() - verify(exactly = 1) { interactor.getCourseStructureFromCache() } - coVerify(exactly = 1) { interactor.getCourseStatus(any()) } + coVerify(exactly = 2) { interactor.getCourseStructure(any()) } + coVerify(exactly = 2) { interactor.getCourseStatus(any()) } assertEquals(somethingWrong, message.await()?.message) assert(viewModel.uiState.value is CourseOutlineUIState.Loading) @@ -287,7 +287,7 @@ class CourseOutlineViewModelTest { @Test fun `getCourseDataInternal success with internet connection`() = runTest(UnconfinedTestDispatcher()) { - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { networkConnection.isOnline() } returns true coEvery { downloadDao.readAllData() } returns flow { emit( @@ -321,11 +321,12 @@ class CourseOutlineViewModelTest { viewModel.uiMessage.first() as? UIMessage.SnackBarMessage } } + viewModel.getCourseData() advanceUntilIdle() - verify(exactly = 1) { interactor.getCourseStructureFromCache() } - coVerify(exactly = 1) { interactor.getCourseStatus(any()) } + coVerify(exactly = 2) { interactor.getCourseStructure(any()) } + coVerify(exactly = 2) { interactor.getCourseStatus(any()) } assert(message.await() == null) assert(viewModel.uiState.value is CourseOutlineUIState.CourseData) @@ -333,7 +334,7 @@ class CourseOutlineViewModelTest { @Test fun `getCourseDataInternal success without internet connection`() = runTest(UnconfinedTestDispatcher()) { - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { networkConnection.isOnline() } returns false coEvery { downloadDao.readAllData() } returns flow { emit( @@ -370,7 +371,7 @@ class CourseOutlineViewModelTest { viewModel.getCourseData() advanceUntilIdle() - verify(exactly = 1) { interactor.getCourseStructureFromCache() } + coVerify(exactly = 2) { interactor.getCourseStructure(any()) } coVerify(exactly = 0) { interactor.getCourseStatus(any()) } assert(message.await() == null) @@ -379,7 +380,7 @@ class CourseOutlineViewModelTest { @Test fun `updateCourseData success with internet connection`() = runTest(UnconfinedTestDispatcher()) { - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { networkConnection.isOnline() } returns true coEvery { downloadDao.readAllData() } returns flow { emit( @@ -417,8 +418,8 @@ class CourseOutlineViewModelTest { viewModel.updateCourseData() advanceUntilIdle() - coVerify(exactly = 2) { interactor.getCourseStructureFromCache() } - coVerify(exactly = 2) { interactor.getCourseStatus(any()) } + coVerify(exactly = 3) { interactor.getCourseStructure(any()) } + coVerify(exactly = 3) { interactor.getCourseStatus(any()) } assert(message.await() == null) assert(viewModel.uiState.value is CourseOutlineUIState.CourseData) @@ -442,7 +443,7 @@ class CourseOutlineViewModelTest { workerController ) coEvery { notifier.notifier } returns flow { emit(CourseStructureUpdated("")) } - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { networkConnection.isOnline() } returns true coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") @@ -454,14 +455,14 @@ class CourseOutlineViewModelTest { viewModel.getCourseData() advanceUntilIdle() - coVerify(exactly = 1) { interactor.getCourseStructureFromCache() } + coVerify(exactly = 2) { interactor.getCourseStructure(any()) } coVerify(exactly = 1) { interactor.getCourseStatus(any()) } } @Test fun `saveDownloadModels test`() = runTest(UnconfinedTestDispatcher()) { every { preferencesManager.videoSettings.wifiDownloadOnly } returns false - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { networkConnection.isWifiConnected() } returns true every { networkConnection.isOnline() } returns true every { @@ -508,7 +509,7 @@ class CourseOutlineViewModelTest { @Test fun `saveDownloadModels only wifi download, with connection`() = runTest(UnconfinedTestDispatcher()) { - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") every { preferencesManager.videoSettings.wifiDownloadOnly } returns true every { networkConnection.isWifiConnected() } returns true @@ -545,7 +546,7 @@ class CourseOutlineViewModelTest { @Test fun `saveDownloadModels only wifi download, without connection`() = runTest(UnconfinedTestDispatcher()) { - every { interactor.getCourseStructureFromCache() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure every { preferencesManager.videoSettings.wifiDownloadOnly } returns true every { networkConnection.isWifiConnected() } returns false every { networkConnection.isOnline() } returns false diff --git a/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt index ba6aa779c..0a398371b 100644 --- a/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt @@ -185,14 +185,14 @@ class CourseSectionViewModelTest { downloadDao, ) - coEvery { interactor.getCourseStructureFromCache() } throws UnknownHostException() - coEvery { interactor.getCourseStructureForVideos() } throws UnknownHostException() + coEvery { interactor.getCourseStructure(any()) } throws UnknownHostException() + coEvery { interactor.getCourseStructureForVideos(any()) } throws UnknownHostException() viewModel.getBlocks("", CourseViewMode.FULL) advanceUntilIdle() - coVerify(exactly = 1) { interactor.getCourseStructureFromCache() } - coVerify(exactly = 0) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 1) { interactor.getCourseStructure(any()) } + coVerify(exactly = 0) { interactor.getCourseStructureForVideos(any()) } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage assertEquals(noInternet, message?.message) @@ -215,14 +215,14 @@ class CourseSectionViewModelTest { downloadDao, ) - coEvery { interactor.getCourseStructureFromCache() } throws Exception() - coEvery { interactor.getCourseStructureForVideos() } throws Exception() + coEvery { interactor.getCourseStructure(any()) } throws Exception() + coEvery { interactor.getCourseStructureForVideos(any()) } throws Exception() viewModel.getBlocks("id2", CourseViewMode.FULL) advanceUntilIdle() - coVerify(exactly = 1) { interactor.getCourseStructureFromCache() } - coVerify(exactly = 0) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 1) { interactor.getCourseStructure(any()) } + coVerify(exactly = 0) { interactor.getCourseStructureForVideos(any()) } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage assertEquals(somethingWrong, message?.message) @@ -247,14 +247,17 @@ class CourseSectionViewModelTest { downloadDao, ) - coEvery { interactor.getCourseStructureFromCache() } returns courseStructure - coEvery { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { downloadDao.readAllData() } returns flow { + emit(listOf(DownloadModelEntity.createFrom(downloadModel))) + } + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure viewModel.getBlocks("id", CourseViewMode.VIDEOS) advanceUntilIdle() - coVerify(exactly = 0) { interactor.getCourseStructureFromCache() } - coVerify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos(any()) } assert(viewModel.uiMessage.value == null) assert(viewModel.uiState.value is CourseSectionUIState.Blocks) @@ -366,8 +369,8 @@ class CourseSectionViewModelTest { ) coEvery { notifier.notifier } returns flow { } - coEvery { interactor.getCourseStructureFromCache() } returns courseStructure - coEvery { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure val mockLifeCycleOwner: LifecycleOwner = mockk() val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner) diff --git a/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt index b92a02f5a..1e5354a95 100644 --- a/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt @@ -1,13 +1,18 @@ package org.openedx.course.presentation.unit.container import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import io.mockk.coEvery +import io.mockk.coVerify import io.mockk.every import io.mockk.mockk -import io.mockk.verify import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.test.* +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before import org.junit.Rule @@ -147,159 +152,161 @@ class CourseUnitContainerViewModelTest { val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } throws UnknownHostException() - every { interactor.getCourseStructureForVideos() } throws UnknownHostException() + coEvery { interactor.getCourseStructure(any()) } throws UnknownHostException() + coEvery { interactor.getCourseStructureForVideos(any()) } throws UnknownHostException() viewModel.loadBlocks(CourseViewMode.FULL) advanceUntilIdle() - verify(exactly = 1) { interactor.getCourseStructureFromCache() } + coVerify(exactly = 1) { interactor.getCourseStructure(any()) } } @Test fun `getBlocks unknown exception`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) + val viewModel = + CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } throws UnknownHostException() - every { interactor.getCourseStructureForVideos() } throws UnknownHostException() + coEvery { interactor.getCourseStructure(any()) } throws UnknownHostException() + coEvery { interactor.getCourseStructureForVideos(any()) } throws UnknownHostException() viewModel.loadBlocks(CourseViewMode.FULL) advanceUntilIdle() - verify(exactly = 1) { interactor.getCourseStructureFromCache() } + coVerify(exactly = 1) { interactor.getCourseStructure(any()) } } @Test fun `getBlocks unknown success`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) + val viewModel = + CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure viewModel.loadBlocks(CourseViewMode.VIDEOS) advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos(any()) } } @Test fun setupCurrentIndex() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + val viewModel = + CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - viewModel.loadBlocks(CourseViewMode.VIDEOS) - viewModel.setupCurrentIndex("id") + viewModel.loadBlocks(CourseViewMode.VIDEOS, "id") advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos(any()) } } @Test fun `getCurrentBlock test`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + val viewModel = + CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - viewModel.loadBlocks(CourseViewMode.VIDEOS) - viewModel.setupCurrentIndex("id") + viewModel.loadBlocks(CourseViewMode.VIDEOS, "id") advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure("") } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos("") } assert(viewModel.getCurrentBlock().id == "id") } @Test fun `moveToPrevBlock null`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + val viewModel = + CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - viewModel.loadBlocks(CourseViewMode.VIDEOS) - viewModel.setupCurrentIndex("id") + viewModel.loadBlocks(CourseViewMode.VIDEOS, "id") advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure("") } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos("") } assert(viewModel.moveToPrevBlock() == null) } @Test fun `moveToPrevBlock not null`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "id", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + val viewModel = + CourseUnitContainerViewModel("", "id", config, interactor, notifier, analytics) + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - viewModel.loadBlocks(CourseViewMode.VIDEOS) - viewModel.setupCurrentIndex("id1") + viewModel.loadBlocks(CourseViewMode.VIDEOS, "id1") advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure("") } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos("") } assert(viewModel.moveToPrevBlock() != null) } @Test fun `moveToNextBlock null`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + val viewModel = + CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - viewModel.loadBlocks(CourseViewMode.VIDEOS) - viewModel.setupCurrentIndex("id3") + viewModel.loadBlocks(CourseViewMode.VIDEOS, "id3") advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure("") } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos("") } assert(viewModel.moveToNextBlock() == null) } @Test fun `moveToNextBlock not null`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "id", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + val viewModel = + CourseUnitContainerViewModel("", "id", config, interactor, notifier, analytics) + coEvery { interactor.getCourseStructure("") } returns courseStructure + coEvery { interactor.getCourseStructureForVideos("") } returns courseStructure - viewModel.loadBlocks(CourseViewMode.VIDEOS) - viewModel.setupCurrentIndex("id") + viewModel.loadBlocks(CourseViewMode.VIDEOS, "id") advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure("") } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos("") } assert(viewModel.moveToNextBlock() != null) } @Test fun `currentIndex isLastIndex`() = runTest { every { notifier.notifier } returns MutableSharedFlow() - val viewModel = CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) - every { interactor.getCourseStructureFromCache() } returns courseStructure - every { interactor.getCourseStructureForVideos() } returns courseStructure + val viewModel = + CourseUnitContainerViewModel("", "", config, interactor, notifier, analytics) + coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - viewModel.loadBlocks(CourseViewMode.VIDEOS) - viewModel.setupCurrentIndex("id3") + viewModel.loadBlocks(CourseViewMode.VIDEOS, "id3") advanceUntilIdle() - verify(exactly = 0) { interactor.getCourseStructureFromCache() } - verify(exactly = 1) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 0) { interactor.getCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructureForVideos(any()) } } } \ No newline at end of file diff --git a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt index 43d057a6c..a2dae8b2e 100644 --- a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt @@ -46,7 +46,7 @@ import org.openedx.core.module.db.FileType import org.openedx.core.presentation.CoreAnalytics import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.CourseDataReady +import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseStructureUpdated import org.openedx.core.system.notifier.VideoNotifier @@ -171,7 +171,7 @@ class CourseVideoViewModelTest { every { resourceManager.getString(R.string.course_can_download_only_with_wifi) } returns cantDownload Dispatchers.setMain(dispatcher) every { config.getApiHostURL() } returns "http://localhost:8000" - every { courseNotifier.notifier } returns flowOf(CourseDataReady(courseStructure)) + every { courseNotifier.notifier } returns flowOf(CourseLoading(false)) } @After @@ -182,7 +182,8 @@ class CourseVideoViewModelTest { @Test fun `getVideos empty list`() = runTest { every { config.isCourseNestedListEnabled() } returns false - every { interactor.getCourseStructureForVideos() } returns courseStructure.copy(blockData = emptyList()) + coEvery { interactor.getCourseStructureForVideos(any()) } returns + courseStructure.copy(blockData = emptyList()) every { downloadDao.readAllData() } returns flow { emit(emptyList()) } every { preferencesManager.videoSettings } returns VideoSettings.default val viewModel = CourseVideoViewModel( @@ -204,7 +205,7 @@ class CourseVideoViewModelTest { viewModel.getVideos() advanceUntilIdle() - coVerify(exactly = 2) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 2) { interactor.getCourseStructureForVideos(any()) } assert(viewModel.uiState.value is CourseVideosUIState.Empty) } @@ -212,7 +213,7 @@ class CourseVideoViewModelTest { @Test fun `getVideos success`() = runTest { every { config.isCourseNestedListEnabled() } returns false - every { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure every { downloadDao.readAllData() } returns flow { emit(emptyList()) } every { preferencesManager.videoSettings } returns VideoSettings.default @@ -236,7 +237,7 @@ class CourseVideoViewModelTest { viewModel.getVideos() advanceUntilIdle() - coVerify(exactly = 2) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 2) { interactor.getCourseStructureForVideos(any()) } assert(viewModel.uiState.value is CourseVideosUIState.CourseData) } @@ -244,10 +245,9 @@ class CourseVideoViewModelTest { @Test fun `updateVideos success`() = runTest { every { config.isCourseNestedListEnabled() } returns false - every { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { courseNotifier.notifier } returns flow { emit(CourseStructureUpdated("")) - emit(CourseDataReady(courseStructure)) } every { downloadDao.readAllData() } returns flow { repeat(5) { @@ -279,7 +279,7 @@ class CourseVideoViewModelTest { advanceUntilIdle() - coVerify(exactly = 2) { interactor.getCourseStructureForVideos() } + coVerify(exactly = 2) { interactor.getCourseStructureForVideos(any()) } assert(viewModel.uiState.value is CourseVideosUIState.CourseData) } @@ -288,7 +288,7 @@ class CourseVideoViewModelTest { fun `setIsUpdating success`() = runTest { every { config.isCourseNestedListEnabled() } returns false every { preferencesManager.videoSettings } returns VideoSettings.default - coEvery { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } advanceUntilIdle() } @@ -312,7 +312,7 @@ class CourseVideoViewModelTest { downloadDao, workerController ) - coEvery { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } every { preferencesManager.videoSettings.wifiDownloadOnly } returns false every { networkConnection.isWifiConnected() } returns true @@ -348,7 +348,7 @@ class CourseVideoViewModelTest { downloadDao, workerController ) - coEvery { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } every { preferencesManager.videoSettings.wifiDownloadOnly } returns true every { networkConnection.isWifiConnected() } returns true @@ -391,7 +391,7 @@ class CourseVideoViewModelTest { every { preferencesManager.videoSettings.wifiDownloadOnly } returns true every { networkConnection.isWifiConnected() } returns false every { networkConnection.isOnline() } returns false - coEvery { interactor.getCourseStructureForVideos() } returns courseStructure + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } coEvery { workerController.saveModels(any()) } returns Unit val message = async { diff --git a/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsScreen.kt b/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsScreen.kt index 2797ed1a6..62ec564b6 100644 --- a/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsScreen.kt +++ b/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsScreen.kt @@ -58,7 +58,7 @@ import org.openedx.discussion.R as discussionR @Composable fun DiscussionTopicsScreen( - discussionTopicsViewModel: DiscussionTopicsViewModel = koinViewModel(), + discussionTopicsViewModel: DiscussionTopicsViewModel, windowSize: WindowSize, fragmentManager: FragmentManager ) { diff --git a/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt b/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt index 5bdd90d70..46552edc9 100644 --- a/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt +++ b/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt @@ -13,7 +13,6 @@ import org.openedx.core.UIMessage import org.openedx.core.extension.isInternetError import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.CourseDataReady import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseRefresh @@ -22,6 +21,8 @@ import org.openedx.discussion.presentation.DiscussionAnalytics import org.openedx.discussion.presentation.DiscussionRouter class DiscussionTopicsViewModel( + val courseId: String, + private val courseTitle: String, private val interactor: DiscussionInteractor, private val resourceManager: ResourceManager, private val analytics: DiscussionAnalytics, @@ -29,9 +30,6 @@ class DiscussionTopicsViewModel( val discussionRouter: DiscussionRouter, ) : BaseViewModel() { - var courseId: String = "" - var courseName: String = "" - private val _uiState = MutableLiveData() val uiState: LiveData get() = _uiState @@ -42,6 +40,8 @@ class DiscussionTopicsViewModel( init { collectCourseNotifier() + + getCourseTopic() } private fun getCourseTopic() { @@ -64,15 +64,15 @@ class DiscussionTopicsViewModel( fun discussionClickedEvent(action: String, data: String, title: String) { when (action) { ALL_POSTS -> { - analytics.discussionAllPostsClickedEvent(courseId, courseName) + analytics.discussionAllPostsClickedEvent(courseId, courseTitle) } FOLLOWING_POSTS -> { - analytics.discussionFollowingClickedEvent(courseId, courseName) + analytics.discussionFollowingClickedEvent(courseId, courseTitle) } TOPIC -> { - analytics.discussionTopicClickedEvent(courseId, courseName, data, title) + analytics.discussionTopicClickedEvent(courseId, courseTitle, data, title) } } } @@ -81,12 +81,6 @@ class DiscussionTopicsViewModel( viewModelScope.launch { courseNotifier.notifier.collect { event -> when (event) { - is CourseDataReady -> { - courseId = event.courseStructure.id - courseName = event.courseStructure.name - getCourseTopic() - } - is CourseRefresh -> { if (event.courseContainerTab == CourseContainerTab.DISCUSSIONS) { getCourseTopic() diff --git a/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt b/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt index fcff13a30..b74cc6644 100644 --- a/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt +++ b/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt @@ -31,7 +31,6 @@ import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.CourseDataReady import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.discussion.domain.interactor.DiscussionInteractor @@ -136,7 +135,7 @@ class DiscussionTopicsViewModelTest { Dispatchers.setMain(dispatcher) every { resourceManager.getString(R.string.core_error_no_connection) } returns noInternet every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong - every { courseNotifier.notifier } returns flowOf(CourseDataReady(courseStructure)) + every { courseNotifier.notifier } returns flowOf(CourseLoading(false)) coEvery { courseNotifier.send(any()) } returns Unit } @@ -147,7 +146,7 @@ class DiscussionTopicsViewModelTest { @Test fun `getCourseTopics no internet exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel(interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) coEvery { interactor.getCourseTopics(any()) } throws UnknownHostException() val message = async { @@ -164,7 +163,7 @@ class DiscussionTopicsViewModelTest { @Test fun `getCourseTopics unknown exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel(interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) coEvery { interactor.getCourseTopics(any()) } throws Exception() val message = async { @@ -181,7 +180,7 @@ class DiscussionTopicsViewModelTest { @Test fun `getCourseTopics success`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel(interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) coEvery { interactor.getCourseTopics(any()) } returns mockk() advanceUntilIdle() @@ -198,7 +197,7 @@ class DiscussionTopicsViewModelTest { @Test fun `updateCourseTopics no internet exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel(interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) coEvery { interactor.getCourseTopics(any()) } throws UnknownHostException() val message = async { @@ -215,7 +214,7 @@ class DiscussionTopicsViewModelTest { @Test fun `updateCourseTopics unknown exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel(interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) coEvery { interactor.getCourseTopics(any()) } throws Exception() val message = async { @@ -232,7 +231,7 @@ class DiscussionTopicsViewModelTest { @Test fun `updateCourseTopics success`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel(interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) coEvery { interactor.getCourseTopics(any()) } returns mockk() val message = async { From 4d78460d76229d0e5b13b91cfa2618f3f943e6d0 Mon Sep 17 00:00:00 2001 From: Volodymyr Chekyrta Date: Tue, 14 May 2024 22:47:47 +0300 Subject: [PATCH 03/38] feat: Course home. Moved certificate access. --- .../outline/CourseOutlineScreen.kt | 23 ++ .../course/presentation/ui/CourseUI.kt | 304 ++++-------------- .../res/drawable/ic_course_certificate.xml | 9 + .../res/drawable/ic_course_completed_mark.xml | 31 -- course/src/main/res/values-uk/strings.xml | 6 +- course/src/main/res/values/strings.xml | 8 +- 6 files changed, 102 insertions(+), 279 deletions(-) create mode 100644 course/src/main/res/drawable/ic_course_certificate.xml delete mode 100644 course/src/main/res/drawable/ic_course_completed_mark.xml diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt index 7e950cba8..6b9f9626d 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt @@ -66,6 +66,7 @@ import org.openedx.course.presentation.CourseRouter 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.CourseMessage import org.openedx.course.presentation.ui.CourseSectionCard import org.openedx.course.presentation.ui.CourseSubSectionItem import java.io.File @@ -272,6 +273,28 @@ private fun CourseOutlineUI( } } } + + val certificate = uiState.courseStructure.certificate + if (certificate?.isCertificateEarned() == true) { + item { + CourseMessage( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 12.dp) + .then(listPadding), + icon = painterResource(R.drawable.ic_course_certificate), + message = stringResource( + R.string.course_you_earned_certificate, + uiState.courseStructure.name + ), + action = stringResource(R.string.course_view_certificate), + onActionClick = { + onCertificateClick(certificate.certificateURL ?: "") + } + ) + } + } + if (uiState.resumeComponent != null) { item { Box(listPadding) { 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 f9f028c0f..50d569308 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 @@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding @@ -45,8 +44,6 @@ import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.filled.Home -import androidx.compose.material.icons.filled.TaskAlt import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -60,32 +57,24 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration 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 import androidx.compose.ui.zIndex -import coil.compose.AsyncImage -import coil.request.ImageRequest import org.jsoup.Jsoup import org.openedx.core.BlockType import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts -import org.openedx.core.domain.model.Certificate import org.openedx.core.domain.model.CourseDatesBannerInfo -import org.openedx.core.domain.model.CourseSharingUtmParameters -import org.openedx.core.domain.model.CoursewareAccess -import org.openedx.core.domain.model.EnrolledCourse -import org.openedx.core.domain.model.EnrolledCourseData -import org.openedx.core.extension.isLinkValid import org.openedx.core.extension.nonZero import org.openedx.core.extension.toFileSize import org.openedx.core.module.db.DownloadModel @@ -97,7 +86,6 @@ import org.openedx.core.ui.OpenEdXButton import org.openedx.core.ui.OpenEdXOutlinedButton import org.openedx.core.ui.displayCutoutForLandscape import org.openedx.core.ui.noRippleClickable -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.appShapes @@ -110,89 +98,6 @@ import subtitleFile.TimedTextObject import java.util.Date import org.openedx.core.R as coreR -@Composable -fun CourseImageHeader( - modifier: Modifier, - apiHostUrl: String, - courseImage: String?, - courseCertificate: Certificate?, - onCertificateClick: (String) -> Unit = {}, - courseName: String, -) { - val configuration = LocalConfiguration.current - val windowSize = rememberWindowSize() - val contentScale = - if (!windowSize.isTablet && configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) { - ContentScale.Fit - } else { - ContentScale.Crop - } - val imageUrl = if (courseImage?.isLinkValid() == true) { - courseImage - } else { - apiHostUrl.dropLast(1) + courseImage - } - Box(modifier = modifier, contentAlignment = Alignment.Center) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(imageUrl) - .error(coreR.drawable.core_no_image_course) - .placeholder(coreR.drawable.core_no_image_course) - .build(), - contentDescription = stringResource( - id = coreR.string.core_accessibility_header_image_for, - courseName - ), - contentScale = contentScale, - modifier = Modifier - .fillMaxSize() - .clip(MaterialTheme.appShapes.cardShape) - ) - if (courseCertificate?.isCertificateEarned() == true) { - Column( - Modifier - .fillMaxSize() - .clip(MaterialTheme.appShapes.cardShape) - .background(MaterialTheme.appColors.certificateForeground), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Icon( - modifier = Modifier.testTag("ic_congratulations"), - painter = painterResource(id = R.drawable.ic_course_completed_mark), - contentDescription = stringResource(id = R.string.course_congratulations), - tint = Color.White - ) - Spacer(Modifier.height(6.dp)) - Text( - modifier = Modifier.testTag("txt_congratulations"), - text = stringResource(id = R.string.course_congratulations), - style = MaterialTheme.appTypography.headlineMedium, - color = Color.White - ) - Spacer(Modifier.height(4.dp)) - Text( - modifier = Modifier.testTag("txt_course_passed"), - text = stringResource(id = R.string.course_passed), - style = MaterialTheme.appTypography.bodyMedium, - color = Color.White - ) - Spacer(Modifier.height(20.dp)) - OpenEdXOutlinedButton( - modifier = Modifier, - borderColor = Color.White, - textColor = MaterialTheme.appColors.buttonText, - text = stringResource(id = R.string.course_view_certificate), - onClick = { - courseCertificate.certificateURL?.let { - onCertificateClick(it) - } - }) - } - } - } -} - @Composable fun CourseSectionCard( block: Block, @@ -377,48 +282,6 @@ fun CardArrow( ) } -@Composable -fun SequentialItem( - block: Block, - onClick: (Block) -> Unit -) { - val icon = if (block.isCompleted()) Icons.Filled.TaskAlt else Icons.Filled.Home - val iconColor = - if (block.isCompleted()) MaterialTheme.appColors.primary else MaterialTheme.appColors.onSurface - Row( - Modifier - .fillMaxWidth() - .padding( - horizontal = 20.dp, - vertical = 12.dp - ) - .clickable { onClick(block) }, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Row(Modifier.weight(1f)) { - Icon( - imageVector = icon, - contentDescription = null, - tint = iconColor - ) - Spacer(modifier = Modifier.width(16.dp)) - Text( - block.displayName, - style = MaterialTheme.appTypography.titleMedium, - color = MaterialTheme.appColors.textPrimary, - overflow = TextOverflow.Ellipsis, - maxLines = 1 - ) - } - Icon( - imageVector = Icons.Filled.ChevronRight, - tint = MaterialTheme.appColors.onSurface, - contentDescription = "Expandable Arrow" - ) - } -} - @Composable fun VideoTitle( text: String, @@ -859,36 +722,6 @@ fun CourseSubSectionItem( } } -@Composable -fun CourseToolbar( - title: String, - onBackClick: () -> Unit -) { - OpenEdXTheme { - Box( - modifier = Modifier - .fillMaxWidth() - .displayCutoutForLandscape() - .zIndex(1f) - .statusBarsPadding(), - contentAlignment = Alignment.CenterStart - ) { - BackBtn { onBackClick() } - Text( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 56.dp), - text = title, - color = MaterialTheme.appColors.textPrimary, - style = MaterialTheme.appTypography.titleMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - textAlign = TextAlign.Center - ) - } - } -} - @Composable fun CourseUnitToolbar( title: String, @@ -1207,6 +1040,49 @@ fun DatesShiftedSnackBar( } } +@Composable +fun CourseMessage( + modifier: Modifier = Modifier, + icon: Painter, + message: String, + action: String? = null, + onActionClick: () -> Unit = {} +) { + Column { + Row( + modifier + .semantics(mergeDescendants = true) {} + .noRippleClickable(onActionClick) + ) { + Icon( + painter = icon, + contentDescription = null, + modifier = Modifier.align(Alignment.CenterVertically), + tint = MaterialTheme.appColors.textPrimary + ) + Column(Modifier.padding(start = 12.dp)) { + Text( + text = message, + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.labelLarge + ) + if (action != null) { + Text( + text = action, + modifier = Modifier.padding(top = 4.dp), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.labelLarge.copy(textDecoration = TextDecoration.Underline) + ) + } + } + } + Divider( + color = MaterialTheme.appColors.divider + ) + } + +} + @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -1263,17 +1139,6 @@ private fun NavigationUnitsButtonsWithNextPreview() { } } -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun SequentialItemPreview() { - OpenEdXTheme { - Surface(color = MaterialTheme.appColors.background) { - SequentialItem(block = mockChapterBlock, onClick = {}) - } - } -} - @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -1290,26 +1155,6 @@ private fun CourseChapterItemPreview() { } } -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun CourseHeaderPreview() { - OpenEdXTheme { - Surface(color = MaterialTheme.appColors.background) { - CourseImageHeader( - modifier = Modifier - .fillMaxWidth() - .height(200.dp) - .padding(6.dp), - apiHostUrl = "", - courseCertificate = Certificate(""), - courseImage = "", - courseName = "" - ) - } - } -} - @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -1361,42 +1206,27 @@ private fun OfflineQueueCardPreview() { } } -private val mockCourse = EnrolledCourse( - auditAccessExpires = Date(), - created = "created", - certificate = Certificate(""), - mode = "mode", - isActive = true, - course = EnrolledCourseData( - id = "id", - name = "Course name", - number = "", - org = "Org", - start = Date(), - startDisplay = "", - startType = "", - end = Date(), - dynamicUpgradeDeadline = "", - subscriptionId = "", - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), - media = null, - courseImage = "", - courseAbout = "", - courseSharingUtmParameters = CourseSharingUtmParameters("", ""), - courseUpdates = "", - courseHandouts = "", - discussionUrl = "", - videoOutline = "", - isSelfPaced = false - ) -) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun CourseMessagePreview() { + OpenEdXTheme { + Surface(color = MaterialTheme.appColors.background) { + CourseMessage( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 12.dp), + icon = painterResource(R.drawable.ic_course_certificate), + message = stringResource( + R.string.course_you_earned_certificate, + "Demo Course" + ), + action = stringResource(R.string.course_view_certificate), + ) + } + } +} + private val mockChapterBlock = Block( id = "id", blockId = "blockId", diff --git a/course/src/main/res/drawable/ic_course_certificate.xml b/course/src/main/res/drawable/ic_course_certificate.xml new file mode 100644 index 000000000..53ca91779 --- /dev/null +++ b/course/src/main/res/drawable/ic_course_certificate.xml @@ -0,0 +1,9 @@ + + + diff --git a/course/src/main/res/drawable/ic_course_completed_mark.xml b/course/src/main/res/drawable/ic_course_completed_mark.xml deleted file mode 100644 index bf3307778..000000000 --- a/course/src/main/res/drawable/ic_course_completed_mark.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - diff --git a/course/src/main/res/values-uk/strings.xml b/course/src/main/res/values-uk/strings.xml index ffbf7c459..14f3487c4 100644 --- a/course/src/main/res/values-uk/strings.xml +++ b/course/src/main/res/values-uk/strings.xml @@ -5,12 +5,8 @@ Одиниці курсу Підрозділи курсу Відео - Ви успішно пройшли курс! Тепер ви можете отримати сертифікат - Ви успішно пройшли курс - Вітаємо! + Вітаємо, ви отримали сертифікат про проходження курсу \"%s\". Переглянути сертифікат - Ви можете отримати сертифікат після проходження курсу (заробіть необхідну оцінку) - Отримати сертифікат Назад Попередня одиниця Далі diff --git a/course/src/main/res/values/strings.xml b/course/src/main/res/values/strings.xml index c6b370267..802065471 100644 --- a/course/src/main/res/values/strings.xml +++ b/course/src/main/res/values/strings.xml @@ -5,12 +5,8 @@ Course units Course subsections Videos - You have passed the course! Now you can get the certificate - You’ve completed the course - Congratulations! - View the certificate - You can get a certificate after completing the course (earn required grade) - Get the certificate + Congratulations, you have earned this course certificate in \"%s\". + View certificate Prev Previous Unit Next From a712170eab2fe9f64ea547320adc92588a4a6ea4 Mon Sep 17 00:00:00 2001 From: Farhan Arshad <43750646+farhan-arshad-dev@users.noreply.github.com> Date: Thu, 23 May 2024 14:43:44 +0500 Subject: [PATCH 04/38] chore: enhance app theme capability for prod edX theme/branding (#262) chore: enhance app theme capability for prod edX theme/branding - Integrate Program config updates - theming/branding code improvements for light and dark modes - Force dark mode for the WebView (beta version) - No major change in the Open edX theme fixes: LEARNER-9783 --- app/src/main/res/layout/fragment_main.xml | 5 +- .../logistration/LogistrationFragment.kt | 5 +- .../presentation/signin/compose/SignInView.kt | 12 +++-- .../presentation/signup/compose/SignUpView.kt | 4 +- .../openedx/auth/presentation/ui/AuthUI.kt | 13 +++-- .../auth/presentation/ui/SocialAuthView.kt | 11 ++-- auth/src/main/res/values-uk/strings.xml | 2 - auth/src/main/res/values/strings.xml | 4 +- build.gradle | 2 + core/build.gradle | 2 + .../org/openedx/core/config/ProgramConfig.kt | 2 +- .../org/openedx/core/extension/ViewExt.kt | 25 +++++++++ .../dialog/appreview/AppReviewUI.kt | 4 +- .../global/app_upgrade/AppUpdateUI.kt | 6 +-- .../java/org/openedx/core/ui/ComposeCommon.kt | 28 ++++++---- .../org/openedx/core/ui/WebContentScreen.kt | 2 + .../org/openedx/core/ui/theme/AppColors.kt | 21 ++++++-- .../java/org/openedx/core/ui/theme/Theme.kt | 42 ++++++++++++--- .../java/org/openedx/core/ui/theme/Type.kt | 2 - .../org/openedx/core/ui/theme/Colors.kt | 54 ++++++++++++++----- .../presentation/ChapterEndFragmentDialog.kt | 16 +++--- .../outline/CourseOutlineScreen.kt | 4 +- .../course/presentation/ui/CourseUI.kt | 14 +++-- .../course/presentation/ui/CourseVideosUI.kt | 1 + .../unit/NotSupportedUnitFragment.kt | 4 +- .../unit/html/HtmlUnitFragment.kt | 5 ++ .../presentation/catalog/CatalogWebView.kt | 5 +- .../detail/CourseDetailsFragment.kt | 4 ++ .../threads/DiscussionThreadsFragment.kt | 8 +-- .../presentation/ui/DiscussionUI.kt | 3 +- .../presentation/edit/EditProfileFragment.kt | 26 +++++---- .../compose/ManageAccountView.kt | 2 +- .../profile/compose/ProfileView.kt | 2 +- .../whatsnew/presentation/ui/WhatsNewUI.kt | 10 ++-- 34 files changed, 246 insertions(+), 104 deletions(-) diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index eb6f37a6f..89cf2914a 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -14,11 +14,11 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - - - \ No newline at end of file + diff --git a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt index 738364c34..ae3d2365e 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -131,7 +132,6 @@ private fun LogistrationScreen( LogistrationLogoView() Text( text = stringResource(id = R.string.pre_auth_title), - color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.headlineSmall, modifier = Modifier .testTag("txt_screen_title") @@ -177,7 +177,8 @@ private fun LogistrationScreen( }, text = stringResource(id = R.string.pre_auth_explore_all_courses), color = MaterialTheme.appColors.primary, - style = MaterialTheme.appTypography.labelLarge + style = MaterialTheme.appTypography.labelLarge, + textDecoration = TextDecoration.Underline ) Spacer(modifier = Modifier.weight(1f)) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index 77e290994..37309cadf 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -195,7 +196,8 @@ internal fun LoginScreen( modifier = Modifier.testTag("txt_${state.agreement.name}"), fullText = linkedText.text, hyperLinks = linkedText.links, - linkTextColor = MaterialTheme.appColors.primary, + linkTextColor = MaterialTheme.appColors.textHyperLink, + linkTextDecoration = TextDecoration.Underline, action = { link -> onEvent(AuthEvent.OpenLink(linkedText.links, link)) }, @@ -264,7 +266,7 @@ private fun AuthForm( onEvent(AuthEvent.ForgotPasswordClick) }, text = stringResource(id = R.string.auth_forgot_password), - color = MaterialTheme.appColors.primary, + color = MaterialTheme.appColors.info_variant, style = MaterialTheme.appTypography.labelLarge ) } @@ -275,6 +277,8 @@ private fun AuthForm( OpenEdXButton( modifier = buttonWidth.testTag("btn_sign_in"), text = stringResource(id = coreR.string.core_sign_in), + textColor = MaterialTheme.appColors.primaryButtonText, + backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, onClick = { onEvent(AuthEvent.SignIn(login = login, password = password)) } @@ -323,8 +327,10 @@ private fun PasswordTextField( onValueChanged(it.text.trim()) }, colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = MaterialTheme.appColors.textFieldText, + backgroundColor = MaterialTheme.appColors.textFieldBackground, unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, - backgroundColor = MaterialTheme.appColors.textFieldBackground + cursorColor = MaterialTheme.appColors.textFieldText, ), shape = MaterialTheme.appShapes.textFieldShape, placeholder = { diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt index 2e2180d83..42fd894df 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt @@ -329,7 +329,7 @@ internal fun SignUpView( modifier = Modifier .testTag("txt_sign_up_title") .fillMaxWidth(), - text = stringResource(id = R.string.auth_sign_up), + text = stringResource(id = coreR.string.core_register), color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.displaySmall ) @@ -437,6 +437,8 @@ internal fun SignUpView( OpenEdXButton( modifier = buttonWidth.testTag("btn_create_account"), text = stringResource(id = R.string.auth_create_account), + textColor = MaterialTheme.appColors.primaryButtonText, + backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, onClick = { showErrorMap.clear() onRegisterClick(AuthType.PASSWORD) diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt index 4f98ea50c..90fb91ee1 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt @@ -44,6 +44,7 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.openedx.auth.R @@ -170,7 +171,8 @@ fun OptionalFields( HyperlinkText( fullText = linkedText.text, hyperLinks = linkedText.links, - linkTextColor = MaterialTheme.appColors.primary, + linkTextColor = MaterialTheme.appColors.textHyperLink, + linkTextDecoration = TextDecoration.Underline, action = { hyperLinkAction?.invoke(linkedText.links, it) }, @@ -250,8 +252,10 @@ fun LoginTextField( onValueChanged(it.text.trim()) }, colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = MaterialTheme.appColors.textFieldText, + backgroundColor = MaterialTheme.appColors.textFieldBackground, unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, - backgroundColor = MaterialTheme.appColors.textFieldBackground + cursorColor = MaterialTheme.appColors.textFieldText, ), shape = MaterialTheme.appShapes.textFieldShape, placeholder = { @@ -332,8 +336,11 @@ fun InputRegistrationField( } }, colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = MaterialTheme.appColors.textFieldText, + backgroundColor = MaterialTheme.appColors.textFieldBackground, + focusedBorderColor = MaterialTheme.appColors.textFieldBorder, unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, - backgroundColor = MaterialTheme.appColors.textFieldBackground + cursorColor = MaterialTheme.appColors.textFieldText, ), shape = MaterialTheme.appShapes.textFieldShape, placeholder = { diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt index 336c09f8f..028439290 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt @@ -45,7 +45,7 @@ internal fun SocialAuthView( .testTag("btn_google_auth") .padding(top = 24.dp) .fillMaxWidth(), - backgroundColor = MaterialTheme.appColors.background, + backgroundColor = MaterialTheme.appColors.authGoogleButtonBackground, borderColor = MaterialTheme.appColors.primary, textColor = Color.Unspecified, onClick = { @@ -62,7 +62,8 @@ internal fun SocialAuthView( modifier = Modifier .testTag("txt_google_auth") .padding(start = 10.dp), - text = stringResource(id = stringRes) + text = stringResource(id = stringRes), + color = MaterialTheme.appColors.primaryButtonBorderedText, ) } } @@ -87,13 +88,13 @@ internal fun SocialAuthView( Icon( painter = painterResource(id = R.drawable.ic_auth_facebook), contentDescription = null, - tint = MaterialTheme.appColors.buttonText, + tint = MaterialTheme.appColors.primaryButtonText, ) Text( modifier = Modifier .testTag("txt_facebook_auth") .padding(start = 10.dp), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, text = stringResource(id = stringRes) ) } @@ -125,7 +126,7 @@ internal fun SocialAuthView( modifier = Modifier .testTag("txt_microsoft_auth") .padding(start = 10.dp), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, text = stringResource(id = stringRes) ) } diff --git a/auth/src/main/res/values-uk/strings.xml b/auth/src/main/res/values-uk/strings.xml index c2c34abef..9c1a1aa69 100644 --- a/auth/src/main/res/values-uk/strings.xml +++ b/auth/src/main/res/values-uk/strings.xml @@ -5,7 +5,6 @@ Електронна пошта Неправильна E-mail адреса Пароль занадто короткий - Ласкаво просимо! Будь ласка, авторизуйтесь, щоб продовжити. Показати додаткові поля Приховати додаткові поля Створити акаунт @@ -15,6 +14,5 @@ Перевірте свою електронну пошту Ми надіслали інструкції щодо відновлення пароля на вашу електронну пошту %s Введіть пароль - Створити новий аккаунт. diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 4f8ce12d8..49b3e0bbd 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -11,7 +11,7 @@ Email or Username Invalid email or username Password is too short - Welcome back! Please authorize to continue. + Welcome back! Sign in to access your courses. Show optional fields Hide optional fields Create account @@ -23,7 +23,7 @@ username@domain.com Enter email or username Enter password - Create new account. + Create an account to start learning today! Complete your registration Sign in with Google Sign in with Facebook diff --git a/build.gradle b/build.gradle index ef9ca662c..250f56863 100644 --- a/build.gradle +++ b/build.gradle @@ -56,6 +56,8 @@ ext { extented_spans_version = "1.3.0" + webkit_version = "1.11.0" + configHelper = new ConfigHelper(projectDir, getCurrentFlavor()) //testing diff --git a/core/build.gradle b/core/build.gradle index f1f091823..f69d633cb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -154,6 +154,8 @@ dependencies { //Play In-App Review api "com.google.android.play:review-ktx:$in_app_review" + api "androidx.webkit:webkit:$webkit_version" + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/core/src/main/java/org/openedx/core/config/ProgramConfig.kt b/core/src/main/java/org/openedx/core/config/ProgramConfig.kt index 55714dadc..c553f8997 100644 --- a/core/src/main/java/org/openedx/core/config/ProgramConfig.kt +++ b/core/src/main/java/org/openedx/core/config/ProgramConfig.kt @@ -14,7 +14,7 @@ data class ProgramConfig( } data class ProgramWebViewConfig( - @SerializedName("PROGRAM_URL") + @SerializedName("BASE_URL") val programUrl: String = "", @SerializedName("PROGRAM_DETAIL_URL_TEMPLATE") val programDetailUrlTemplate: String = "", diff --git a/core/src/main/java/org/openedx/core/extension/ViewExt.kt b/core/src/main/java/org/openedx/core/extension/ViewExt.kt index 9146a3159..ebd007d3d 100644 --- a/core/src/main/java/org/openedx/core/extension/ViewExt.kt +++ b/core/src/main/java/org/openedx/core/extension/ViewExt.kt @@ -3,12 +3,15 @@ package org.openedx.core.extension import android.content.Context import android.content.res.Resources import android.graphics.Rect +import android.os.Build import android.util.DisplayMetrics import android.view.View import android.view.ViewGroup import android.webkit.WebView import android.widget.Toast import androidx.fragment.app.DialogFragment +import androidx.webkit.WebSettingsCompat +import androidx.webkit.WebViewFeature import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.openedx.core.system.AppCookieManager @@ -61,3 +64,25 @@ fun WebView.loadUrl(url: String, scope: CoroutineScope, cookieManager: AppCookie loadUrl(url) } } + +fun WebView.applyDarkModeIfEnabled(isDarkTheme: Boolean) { + if (isDarkTheme && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + settings.setAlgorithmicDarkeningAllowed(true) + } else { + // Switch WebView to dark mode; uses default dark theme + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + WebSettingsCompat.setForceDark( + settings, + WebSettingsCompat.FORCE_DARK_ON + ) + } + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { + WebSettingsCompat.setForceDarkStrategy( + settings, + WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING + ) + } + } + } +} diff --git a/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt b/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt index e2d6a471f..b924cd543 100644 --- a/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt +++ b/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt @@ -320,8 +320,8 @@ fun DefaultTextButton( val textColor: Color val backgroundColor: Color if (isEnabled) { - textColor = MaterialTheme.appColors.buttonText - backgroundColor = MaterialTheme.appColors.buttonBackground + textColor = MaterialTheme.appColors.primaryButtonText + backgroundColor = MaterialTheme.appColors.primaryButtonBackground } else { textColor = MaterialTheme.appColors.inactiveButtonText backgroundColor = MaterialTheme.appColors.inactiveButtonBackground diff --git a/core/src/main/java/org/openedx/core/presentation/global/app_upgrade/AppUpdateUI.kt b/core/src/main/java/org/openedx/core/presentation/global/app_upgrade/AppUpdateUI.kt index f0502b49d..3f8dd6fa9 100644 --- a/core/src/main/java/org/openedx/core/presentation/global/app_upgrade/AppUpdateUI.kt +++ b/core/src/main/java/org/openedx/core/presentation/global/app_upgrade/AppUpdateUI.kt @@ -292,7 +292,7 @@ fun DefaultTextButton( .testTag("btn_primary") .height(42.dp), colors = ButtonDefaults.buttonColors( - backgroundColor = MaterialTheme.appColors.buttonBackground + backgroundColor = MaterialTheme.appColors.primaryButtonBackground ), elevation = null, shape = MaterialTheme.appShapes.navigationButtonShape, @@ -305,7 +305,7 @@ fun DefaultTextButton( Text( modifier = Modifier.testTag("txt_primary"), text = text, - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, style = MaterialTheme.appTypography.labelLarge ) } @@ -401,4 +401,4 @@ private fun AppUpgradeRecommendDialogPreview() { onUpdateClick = {} ) } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt index 3b97742f1..212014177 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt @@ -434,7 +434,7 @@ fun HyperlinkText( append(fullText) addStyle( style = SpanStyle( - color = MaterialTheme.appColors.textPrimary, + color = MaterialTheme.appColors.textPrimaryLight, fontSize = fontSize ), start = 0, @@ -450,7 +450,7 @@ fun HyperlinkText( color = linkTextColor, fontSize = fontSize, fontWeight = linkTextFontWeight, - textDecoration = linkTextDecoration + textDecoration = linkTextDecoration, ), start = startIndex, end = endIndex @@ -635,7 +635,8 @@ fun SheetContent( .padding(10.dp), textAlign = TextAlign.Center, style = MaterialTheme.appTypography.titleMedium, - text = title + text = title, + color = MaterialTheme.appColors.onBackground ) SearchBarStateless( modifier = Modifier @@ -667,6 +668,7 @@ fun SheetContent( onItemClick(item) } .padding(vertical = 12.dp), + color = MaterialTheme.appColors.onBackground, text = item.name, style = MaterialTheme.appTypography.bodyLarge, textAlign = TextAlign.Center @@ -1049,8 +1051,9 @@ fun OpenEdXButton( text: String = "", onClick: () -> Unit, enabled: Boolean = true, - backgroundColor: Color = MaterialTheme.appColors.buttonBackground, - content: (@Composable RowScope.() -> Unit)? = null, + textColor: Color = MaterialTheme.appColors.primaryButtonText, + backgroundColor: Color = MaterialTheme.appColors.primaryButtonBackground, + content: (@Composable RowScope.() -> Unit)? = null ) { Button( modifier = Modifier @@ -1068,7 +1071,7 @@ fun OpenEdXButton( Text( modifier = Modifier.testTag("txt_${text.tagId()}"), text = text, - color = MaterialTheme.appColors.buttonText, + color = textColor, style = MaterialTheme.appTypography.labelLarge ) } else { @@ -1084,6 +1087,7 @@ fun OpenEdXOutlinedButton( borderColor: Color, textColor: Color, text: String = "", + enabled: Boolean = true, onClick: () -> Unit, content: (@Composable RowScope.() -> Unit)? = null, ) { @@ -1093,6 +1097,7 @@ fun OpenEdXOutlinedButton( .then(modifier) .height(42.dp), onClick = onClick, + enabled = enabled, border = BorderStroke(1.dp, borderColor), shape = MaterialTheme.appShapes.buttonShape, colors = ButtonDefaults.outlinedButtonColors(backgroundColor = backgroundColor) @@ -1163,7 +1168,9 @@ fun ConnectionErrorView( modifier = Modifier .widthIn(Dp.Unspecified, 162.dp), text = stringResource(id = R.string.core_reload), - onClick = onReloadClick + textColor = MaterialTheme.appColors.primaryButtonText, + backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, + onClick = onReloadClick, ) } } @@ -1180,6 +1187,8 @@ fun AuthButtonsPanel( .width(0.dp) .weight(1f), text = stringResource(id = R.string.core_register), + textColor = MaterialTheme.appColors.primaryButtonText, + backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, onClick = { onRegisterClick() } ) @@ -1190,8 +1199,9 @@ fun AuthButtonsPanel( .padding(start = 16.dp), text = stringResource(id = R.string.core_sign_in), onClick = { onSignInClick() }, - borderColor = MaterialTheme.appColors.textFieldBorder, - textColor = MaterialTheme.appColors.primary + textColor = MaterialTheme.appColors.secondaryButtonBorderedText, + backgroundColor = MaterialTheme.appColors.secondaryButtonBorderedBackground, + borderColor = MaterialTheme.appColors.secondaryButtonBorder, ) } } diff --git a/core/src/main/java/org/openedx/core/ui/WebContentScreen.kt b/core/src/main/java/org/openedx/core/ui/WebContentScreen.kt index c9c7c4ba1..06aa70ea2 100644 --- a/core/src/main/java/org/openedx/core/ui/WebContentScreen.kt +++ b/core/src/main/java/org/openedx/core/ui/WebContentScreen.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.zIndex +import org.openedx.core.extension.applyDarkModeIfEnabled import org.openedx.core.extension.isEmailValid import org.openedx.core.extension.replaceLinkTags import org.openedx.core.ui.theme.appColors @@ -195,6 +196,7 @@ private fun WebViewContent( contentUrl?.let { loadUrl(it) } + applyDarkModeIfEnabled(isDarkTheme) } }, update = { webView -> diff --git a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt index 4b7a0ba10..968fd9fe3 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt @@ -8,6 +8,8 @@ data class AppColors( val textPrimary: Color, val textPrimaryVariant: Color, + val textPrimaryLight: Color, + val textHyperLink: Color, val textSecondary: Color, val textDark: Color, val textAccent: Color, @@ -19,9 +21,18 @@ data class AppColors( val textFieldText: Color, val textFieldHint: Color, - val buttonBackground: Color, - val buttonSecondaryBackground: Color, - val buttonText: Color, + val primaryButtonBackground: Color, + val primaryButtonText: Color, + val primaryButtonBorder: Color, + val primaryButtonBorderedText: Color, + + // The default secondary button styling is identical to the primary button styling. + // However, you can customize it if your brand utilizes two accent colors. + val secondaryButtonBackground: Color, + val secondaryButtonText: Color, + val secondaryButtonBorder: Color, + val secondaryButtonBorderedBackground: Color, + val secondaryButtonBorderedText: Color, val cardViewBackground: Color, val cardViewBorder: Color, @@ -31,6 +42,9 @@ data class AppColors( val bottomSheetToggle: Color, val warning: Color, val info: Color, + val info_variant: Color, + val onWarning: Color, + val onInfo: Color, val rateStars: Color, val inactiveButtonBackground: Color, @@ -44,6 +58,7 @@ data class AppColors( val datesSectionBarNextWeek: Color, val datesSectionBarUpcoming: Color, + val authGoogleButtonBackground: Color, val authFacebookButtonBackground: Color, val authMicrosoftButtonBackground: Color, diff --git a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt index 1ffa3c73d..291192c1c 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt @@ -27,10 +27,12 @@ private val DarkColorPalette = AppColors( ), textPrimary = dark_text_primary, textPrimaryVariant = dark_text_primary_variant, + textPrimaryLight = dark_text_primary_light, textSecondary = dark_text_secondary, textDark = dark_text_dark, textAccent = dark_text_accent, textWarning = dark_text_warning, + textHyperLink = dark_text_hyper_link, textFieldBackground = dark_text_field_background, textFieldBackgroundVariant = dark_text_field_background_variant, @@ -38,9 +40,16 @@ private val DarkColorPalette = AppColors( textFieldText = dark_text_field_text, textFieldHint = dark_text_field_hint, - buttonBackground = dark_button_background, - buttonSecondaryBackground = dark_button_secondary_background, - buttonText = dark_button_text, + primaryButtonBackground = dark_primary_button_background, + primaryButtonText = dark_primary_button_text, + primaryButtonBorder = dark_primary_button_border, + primaryButtonBorderedText = dark_primary_button_bordered_text, + + secondaryButtonBackground = dark_secondary_button_background, + secondaryButtonText = dark_secondary_button_text, + secondaryButtonBorder = dark_secondary_button_border, + secondaryButtonBorderedBackground = dark_secondary_button_bordered_background, + secondaryButtonBorderedText = dark_secondary_button_bordered_text, cardViewBackground = dark_card_view_background, cardViewBorder = dark_card_view_border, @@ -51,10 +60,13 @@ private val DarkColorPalette = AppColors( warning = dark_warning, info = dark_info, + info_variant = dark_info_variant, + onWarning = dark_onWarning, + onInfo = dark_onInfo, rateStars = dark_rate_stars, inactiveButtonBackground = dark_inactive_button_background, - inactiveButtonText = dark_button_text, + inactiveButtonText = dark_primary_button_text, accessGreen = dark_access_green, @@ -64,6 +76,7 @@ private val DarkColorPalette = AppColors( datesSectionBarNextWeek = dark_dates_section_bar_next_week, datesSectionBarUpcoming = dark_dates_section_bar_upcoming, + authGoogleButtonBackground = dark_auth_google_button_background, authFacebookButtonBackground = dark_auth_facebook_button_background, authMicrosoftButtonBackground = dark_auth_microsoft_button_background, @@ -98,10 +111,12 @@ private val LightColorPalette = AppColors( ), textPrimary = light_text_primary, textPrimaryVariant = light_text_primary_variant, + textPrimaryLight = light_text_primary_light, textSecondary = light_text_secondary, textDark = light_text_dark, textAccent = light_text_accent, textWarning = light_text_warning, + textHyperLink = light_text_hyper_link, textFieldBackground = light_text_field_background, textFieldBackgroundVariant = light_text_field_background_variant, @@ -109,9 +124,16 @@ private val LightColorPalette = AppColors( textFieldText = light_text_field_text, textFieldHint = light_text_field_hint, - buttonBackground = light_button_background, - buttonSecondaryBackground = light_button_secondary_background, - buttonText = light_button_text, + primaryButtonBackground = light_primary_button_background, + primaryButtonText = light_primary_button_text, + primaryButtonBorder = light_primary_button_border, + primaryButtonBorderedText = light_primary_button_bordered_text, + + secondaryButtonBackground = light_secondary_button_background, + secondaryButtonText = light_secondary_button_text, + secondaryButtonBorder = light_secondary_button_border, + secondaryButtonBorderedBackground = light_secondary_button_bordered_background, + secondaryButtonBorderedText = light_secondary_button_bordered_text, cardViewBackground = light_card_view_background, cardViewBorder = light_card_view_border, @@ -122,10 +144,13 @@ private val LightColorPalette = AppColors( warning = light_warning, info = light_info, + info_variant = light_info_variant, + onWarning = light_onWarning, + onInfo = light_onInfo, rateStars = light_rate_stars, inactiveButtonBackground = light_inactive_button_background, - inactiveButtonText = light_button_text, + inactiveButtonText = light_primary_button_text, accessGreen = light_access_green, @@ -135,6 +160,7 @@ private val LightColorPalette = AppColors( datesSectionBarNextWeek = light_dates_section_bar_next_week, datesSectionBarUpcoming = light_dates_section_bar_upcoming, + authGoogleButtonBackground = light_auth_google_button_background, authFacebookButtonBackground = light_auth_facebook_button_background, authMicrosoftButtonBackground = light_auth_microsoft_button_background, diff --git a/core/src/main/java/org/openedx/core/ui/theme/Type.kt b/core/src/main/java/org/openedx/core/ui/theme/Type.kt index edd2afcc7..0160196f9 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Type.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Type.kt @@ -34,7 +34,6 @@ data class AppTypography( val fontFamily = FontFamily( Font(R.font.regular, FontWeight.Black, FontStyle.Normal), Font(R.font.bold, FontWeight.Bold, FontStyle.Normal), - Font(R.font.bold, FontWeight.Bold, FontStyle.Normal), Font(R.font.extra_light, FontWeight.Light, FontStyle.Normal), Font(R.font.light, FontWeight.Light, FontStyle.Normal), Font(R.font.medium, FontWeight.Medium, FontStyle.Normal), @@ -43,7 +42,6 @@ val fontFamily = FontFamily( Font(R.font.thin, FontWeight.Thin, FontStyle.Normal), ) - internal val LocalTypography = staticCompositionLocalOf { AppTypography( displayLarge = TextStyle( diff --git a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt index 1cc4c3495..0bb1114c8 100644 --- a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt @@ -10,24 +10,38 @@ val light_background = Color.White val light_surface = Color(0xFFF7F7F8) val light_error = Color(0xFFFF3D71) val light_onPrimary = Color.White -val light_onSecondary = Color.Black +val light_onSecondary = Color.White val light_onBackground = Color.Black val light_onSurface = Color.Black val light_onError = Color.White +val light_onWarning = Color.White +val light_onInfo = Color.White +val light_info_variant = Color(0xFF3C68FF) val light_text_primary = Color(0xFF212121) val light_text_primary_variant = Color(0xFF3D4964) +val light_text_primary_light = light_text_primary val light_text_secondary = Color(0xFFB3B3B3) val light_text_dark = Color(0xFF19212F) val light_text_accent = Color(0xFF3C68FF) -val light_text_warning= Color(0xFF19212F) +val light_text_warning = Color(0xFF19212F) val light_text_field_background = Color(0xFFF7F7F8) val light_text_field_background_variant = Color.White val light_text_field_border = Color(0xFF97A5BB) val light_text_field_text = Color(0xFF3D4964) val light_text_field_hint = Color(0xFF97A5BB) -val light_button_background = Color(0xFF3C68FF) -val light_button_secondary_background = Color(0xFF79889F) -val light_button_text = Color.White +val light_text_hyper_link = Color(0xFF3C68FF) + +val light_primary_button_background = Color(0xFF3C68FF) +val light_primary_button_border = Color(0xFF97A5BB) +val light_primary_button_text = Color.White +val light_primary_button_bordered_text = Color(0xFF3C68FF) + +val light_secondary_button_background = light_primary_button_background +val light_secondary_button_text = light_primary_button_text +val light_secondary_button_border = light_primary_button_border +val light_secondary_button_bordered_background = Color.White +val light_secondary_button_bordered_text = light_primary_button_bordered_text + val light_card_view_background = Color(0xFFF9FAFB) val light_card_view_border = Color(0xFFCCD4E0) val light_divider = Color(0xFFCCD4E0) @@ -37,13 +51,13 @@ val light_warning = Color(0xFFFFC94D) val light_info = Color(0xFF42AAFF) val light_rate_stars = Color(0xFFFFC94D) val light_inactive_button_background = Color(0xFFCCD4E0) -val light_inactive_button_text = Color(0xFF3D4964) val light_access_green = Color(0xFF23BCA0) val light_dates_section_bar_past_due = light_warning val light_dates_section_bar_today = light_info val light_dates_section_bar_this_week = light_text_primary_variant val light_dates_section_bar_next_week = light_text_field_border val light_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val light_auth_google_button_background = Color.White val light_auth_facebook_button_background = Color(0xFF0866FF) val light_auth_microsoft_button_background = Color(0xFA000000) val light_component_horizontal_progress_completed_and_selected = Color(0xFF30a171) @@ -66,40 +80,54 @@ val dark_background = Color(0xFF19212F) val dark_surface = Color(0xFF273346) val dark_error = Color(0xFFFF3D71) val dark_onPrimary = Color.Black -val dark_onSecondary = Color.Black +val dark_onSecondary = Color.White val dark_onBackground = Color.White val dark_onSurface = Color.White val dark_onError = Color.Black val dark_text_primary = Color.White -val dark_text_primary_variant = Color(0xFF79889F) +val dark_text_primary_light = dark_text_primary +val dark_text_primary_variant = Color.White val dark_text_secondary = Color(0xFFB3B3B3) val dark_text_dark = Color.White val dark_text_accent = Color(0xFF879FF5) -val dark_text_warning= Color(0xFF19212F) +val dark_text_warning = Color(0xFF19212F) val dark_text_field_background = Color(0xFF273346) val dark_text_field_background_variant = Color(0xFF273346) val dark_text_field_border = Color(0xFF4E5A70) val dark_text_field_text = Color.White val dark_text_field_hint = Color(0xFF79889F) -val dark_button_background = Color(0xFF5478F9) -val dark_button_secondary_background = Color(0xFF79889F) -val dark_button_text = Color.White +val dark_text_hyper_link = Color(0xFF5478F9) + +val dark_primary_button_background = Color(0xFF5478F9) +val dark_primary_button_text = Color.White +val dark_primary_button_border = Color(0xFF4E5A70) +val dark_primary_button_bordered_text = Color(0xFF5478F9) + +val dark_secondary_button_background = dark_primary_button_background +val dark_secondary_button_text = dark_primary_button_text +val dark_secondary_button_border = dark_primary_button_border +val dark_secondary_button_bordered_background = Color(0xFF19212F) +val dark_secondary_button_bordered_text = dark_primary_button_bordered_text + val dark_card_view_background = Color(0xFF273346) val dark_card_view_border = Color(0xFF4E5A70) val dark_divider = Color(0xFF4E5A70) val dark_certificate_foreground = Color(0xD92EB865) val dark_bottom_sheet_toggle = Color(0xFF4E5A70) val dark_warning = Color(0xFFFFC248) +val dark_onWarning = Color.White val dark_info = Color(0xFF0095FF) +val dark_info_variant = Color(0xFF5478F9) +val dark_onInfo = Color.White val dark_rate_stars = Color(0xFFFFC94D) val dark_inactive_button_background = Color(0xFFCCD4E0) -val dark_inactive_button_text = Color(0xFF3D4964) val dark_access_green = Color(0xFF23BCA0) val dark_dates_section_bar_past_due = dark_warning val dark_dates_section_bar_today = dark_info val dark_dates_section_bar_this_week = dark_text_primary_variant val dark_dates_section_bar_next_week = dark_text_field_border val dark_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val dark_auth_google_button_background = Color(0xFF19212F) val dark_auth_facebook_button_background = Color(0xFF0866FF) val dark_auth_microsoft_button_background = Color(0xFA000000) val dark_component_horizontal_progress_completed_and_selected = Color(0xFF30a171) diff --git a/course/src/main/java/org/openedx/course/presentation/ChapterEndFragmentDialog.kt b/course/src/main/java/org/openedx/course/presentation/ChapterEndFragmentDialog.kt index e84766780..c416aa497 100644 --- a/course/src/main/java/org/openedx/course/presentation/ChapterEndFragmentDialog.kt +++ b/course/src/main/java/org/openedx/course/presentation/ChapterEndFragmentDialog.kt @@ -209,7 +209,7 @@ private fun ChapterEndDialogScreen( TextIcon( text = stringResource(id = R.string.course_next_section), painter = painterResource(org.openedx.core.R.drawable.core_ic_forward), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, textStyle = MaterialTheme.appTypography.labelLarge, iconModifier = Modifier.rotate(if (isVerticalNavigation) 90f else 0f) ) @@ -219,15 +219,15 @@ private fun ChapterEndDialogScreen( Spacer(Modifier.height(16.dp)) } OpenEdXOutlinedButton( - borderColor = MaterialTheme.appColors.buttonBackground, - textColor = MaterialTheme.appColors.buttonBackground, + borderColor = MaterialTheme.appColors.primaryButtonBackground, + textColor = MaterialTheme.appColors.primaryButtonBackground, text = stringResource(id = R.string.course_back_to_outline), onClick = onBackButtonClick, content = { AutoSizeText( text = stringResource(id = R.string.course_back_to_outline), style = MaterialTheme.appTypography.bodyMedium, - color = MaterialTheme.appColors.buttonBackground + color = MaterialTheme.appColors.primaryButtonBorderedText ) } ) @@ -326,7 +326,7 @@ private fun ChapterEndDialogScreenLandscape( TextIcon( text = stringResource(id = R.string.course_next_section), painter = painterResource(org.openedx.core.R.drawable.core_ic_forward), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, textStyle = MaterialTheme.appTypography.labelLarge ) }, @@ -335,15 +335,15 @@ private fun ChapterEndDialogScreenLandscape( Spacer(Modifier.height(16.dp)) } OpenEdXOutlinedButton( - borderColor = MaterialTheme.appColors.buttonBackground, - textColor = MaterialTheme.appColors.buttonBackground, + borderColor = MaterialTheme.appColors.primaryButtonBackground, + textColor = MaterialTheme.appColors.primaryButtonBackground, text = stringResource(id = R.string.course_back_to_outline), onClick = onBackButtonClick, content = { AutoSizeText( text = stringResource(id = R.string.course_back_to_outline), style = MaterialTheme.appTypography.bodyMedium, - color = MaterialTheme.appColors.buttonBackground + color = MaterialTheme.appColors.primaryButtonBorderedText ) } ) diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt index 6b9f9626d..3bdc9e622 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt @@ -440,7 +440,7 @@ private fun ResumeCourse( TextIcon( text = stringResource(id = R.string.course_resume), painter = painterResource(id = CoreR.drawable.core_ic_forward), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, textStyle = MaterialTheme.appTypography.labelLarge ) } @@ -499,7 +499,7 @@ private fun ResumeCourseTablet( TextIcon( text = stringResource(id = R.string.course_resume), painter = painterResource(id = CoreR.drawable.core_ic_forward), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, textStyle = MaterialTheme.appTypography.labelLarge ) } 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 50d569308..011003ede 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 @@ -339,7 +339,7 @@ fun NavigationUnitsButtons( colors = ButtonDefaults.outlinedButtonColors( backgroundColor = MaterialTheme.appColors.background ), - border = BorderStroke(1.dp, MaterialTheme.appColors.primary), + border = BorderStroke(1.dp, MaterialTheme.appColors.primaryButtonBorder), elevation = null, shape = MaterialTheme.appShapes.navigationButtonShape, onClick = onPrevClick, @@ -368,7 +368,7 @@ fun NavigationUnitsButtons( modifier = Modifier .height(42.dp), colors = ButtonDefaults.buttonColors( - backgroundColor = MaterialTheme.appColors.buttonBackground + backgroundColor = MaterialTheme.appColors.primaryButtonBackground ), elevation = null, shape = MaterialTheme.appShapes.navigationButtonShape, @@ -380,7 +380,7 @@ fun NavigationUnitsButtons( ) { Text( text = nextButtonText, - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, style = MaterialTheme.appTypography.labelLarge ) Spacer(Modifier.width(8.dp)) @@ -388,7 +388,7 @@ fun NavigationUnitsButtons( modifier = Modifier.rotate(if (isVerticalNavigation || !hasNextBlock) 0f else -90f), painter = nextButtonIcon, contentDescription = null, - tint = MaterialTheme.appColors.buttonText + tint = MaterialTheme.appColors.primaryButtonText ) } } @@ -516,7 +516,11 @@ fun VideoSubtitles( val scaffoldState = rememberScaffoldState() val subtitles = timedTextObject.captions.values.toList() Scaffold(scaffoldState = scaffoldState) { - Column(Modifier.padding(it)) { + Column( + modifier = Modifier + .padding(it) + .background(color = MaterialTheme.appColors.background) + ) { Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt index c69e26c0d..16fd90992 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt @@ -630,6 +630,7 @@ private fun AllVideosDownloadItem( } }, colors = SwitchDefaults.colors( + uncheckedThumbColor = MaterialTheme.appColors.primary, checkedThumbColor = MaterialTheme.appColors.primary, checkedTrackColor = MaterialTheme.appColors.primary ) diff --git a/course/src/main/java/org/openedx/course/presentation/unit/NotSupportedUnitFragment.kt b/course/src/main/java/org/openedx/course/presentation/unit/NotSupportedUnitFragment.kt index bdf5dcd8b..0aaae4a3c 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/NotSupportedUnitFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/NotSupportedUnitFragment.kt @@ -139,14 +139,14 @@ private fun NotSupportedUnitScreen( .height(42.dp), shape = MaterialTheme.appShapes.buttonShape, colors = ButtonDefaults.buttonColors( - backgroundColor = MaterialTheme.appColors.buttonBackground + backgroundColor = MaterialTheme.appColors.primaryButtonBackground ), onClick = { uriHandler.openUri(uri) }) { Text( text = stringResource(id = courseR.string.course_open_in_browser), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, style = MaterialTheme.appTypography.labelLarge ) } diff --git a/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt b/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt index 3a49e0e4b..392fa07fa 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitFragment.kt @@ -49,6 +49,7 @@ import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import kotlinx.coroutines.launch import org.koin.androidx.viewmodel.ext.android.viewModel +import org.openedx.core.extension.applyDarkModeIfEnabled import org.openedx.core.extension.isEmailValid import org.openedx.core.extension.loadUrl import org.openedx.core.system.AppCookieManager @@ -212,6 +213,8 @@ private fun HTMLContentView( ) } + val isDarkTheme = isSystemInDarkTheme() + AndroidView( modifier = Modifier .then(screenWidth) @@ -287,11 +290,13 @@ private fun HTMLContentView( setSupportZoom(true) loadsImagesAutomatically = true domStorageEnabled = true + } isVerticalScrollBarEnabled = false isHorizontalScrollBarEnabled = false loadUrl(url, coroutineScope, cookieManager) + applyDarkModeIfEnabled(isDarkTheme) } }, update = { webView -> diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/catalog/CatalogWebView.kt b/discovery/src/main/java/org/openedx/discovery/presentation/catalog/CatalogWebView.kt index 42531f8a0..373516b0a 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/catalog/CatalogWebView.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/catalog/CatalogWebView.kt @@ -3,9 +3,11 @@ package org.openedx.discovery.presentation.catalog import android.annotation.SuppressLint import android.webkit.WebResourceRequest import android.webkit.WebView +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext +import org.openedx.core.extension.applyDarkModeIfEnabled import org.openedx.discovery.presentation.catalog.WebViewLink.Authority as linkAuthority @SuppressLint("SetJavaScriptEnabled", "ComposableNaming") @@ -20,7 +22,7 @@ fun CatalogWebViewScreen( onUriClick: (String, linkAuthority) -> Unit, ): WebView { val context = LocalContext.current - + val isDarkTheme = isSystemInDarkTheme() return remember { WebView(context).apply { webViewClient = object : DefaultWebViewClient( @@ -93,6 +95,7 @@ fun CatalogWebViewScreen( isHorizontalScrollBarEnabled = false loadUrl(url) + applyDarkModeIfEnabled(isDarkTheme) } } } diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt b/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt index 813994307..0060199da 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt @@ -14,6 +14,7 @@ import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -80,6 +81,7 @@ import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import org.openedx.core.UIMessage import org.openedx.core.domain.model.Media +import org.openedx.core.extension.applyDarkModeIfEnabled import org.openedx.core.extension.isEmailValid import org.openedx.core.ui.AuthButtonsPanel import org.openedx.core.ui.HandleUIMessage @@ -625,6 +627,7 @@ private fun CourseDescription( onWebPageLoaded: () -> Unit ) { val context = LocalContext.current + val isDarkTheme = isSystemInDarkTheme() AndroidView(modifier = Modifier.then(modifier), factory = { WebView(context).apply { webViewClient = object : WebViewClient() { @@ -674,6 +677,7 @@ private fun CourseDescription( StandardCharsets.UTF_8.name(), null ) + applyDarkModeIfEnabled(isDarkTheme) } }) } diff --git a/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionThreadsFragment.kt b/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionThreadsFragment.kt index 99bf4f26e..34a08ebb2 100644 --- a/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionThreadsFragment.kt +++ b/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionThreadsFragment.kt @@ -393,7 +393,7 @@ private fun DiscussionThreadsScreen( text = filterType.first, painter = painterResource(id = discussionR.drawable.discussion_ic_filter), textStyle = MaterialTheme.appTypography.labelMedium, - color = MaterialTheme.appColors.textAccent, + color = MaterialTheme.appColors.textPrimary, onClick = { currentSelectedList = FilterType.type expandedList = listOf( @@ -423,7 +423,7 @@ private fun DiscussionThreadsScreen( text = sortType.first, painter = painterResource(id = discussionR.drawable.discussion_ic_sort), textStyle = MaterialTheme.appTypography.labelMedium, - color = MaterialTheme.appColors.textAccent, + color = MaterialTheme.appColors.textPrimary, onClick = { currentSelectedList = SortType.type expandedList = listOf( @@ -475,7 +475,7 @@ private fun DiscussionThreadsScreen( Modifier .size(40.dp) .clip(CircleShape) - .background(MaterialTheme.appColors.primary) + .background(MaterialTheme.appColors.secondaryButtonBackground) .clickable { onCreatePostClick() }, @@ -485,7 +485,7 @@ private fun DiscussionThreadsScreen( modifier = Modifier.size(16.dp), painter = painterResource(id = discussionR.drawable.discussion_ic_add_comment), contentDescription = stringResource(id = discussionR.string.discussion_add_comment), - tint = MaterialTheme.appColors.buttonText + tint = MaterialTheme.appColors.primaryButtonText ) } } diff --git a/discussion/src/main/java/org/openedx/discussion/presentation/ui/DiscussionUI.kt b/discussion/src/main/java/org/openedx/discussion/presentation/ui/DiscussionUI.kt index 7d2242850..cd87e0498 100644 --- a/discussion/src/main/java/org/openedx/discussion/presentation/ui/DiscussionUI.kt +++ b/discussion/src/main/java/org/openedx/discussion/presentation/ui/DiscussionUI.kt @@ -587,11 +587,10 @@ fun ThreadItem( thread.commentCount - 1 ), painter = painterResource(id = R.drawable.discussion_ic_responses), - color = MaterialTheme.appColors.textAccent, + color = MaterialTheme.appColors.textPrimary, textStyle = MaterialTheme.appTypography.labelLarge ) } - } diff --git a/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt index 907b3942a..5fc9e9a78 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt @@ -648,7 +648,7 @@ private fun EditProfileScreen( }, painter = painterResource(id = R.drawable.profile_ic_edit_image), contentDescription = null, - tint = Color.White + tint = MaterialTheme.appColors.onPrimary ) } Spacer(modifier = Modifier.height(20.dp)) @@ -949,10 +949,12 @@ private fun SelectableField( ) } else { TextFieldDefaults.outlinedTextFieldColors( + textColor = MaterialTheme.appColors.textFieldText, + backgroundColor = MaterialTheme.appColors.textFieldBackground, unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, + cursorColor = MaterialTheme.appColors.textFieldText, disabledBorderColor = MaterialTheme.appColors.textFieldBorder, - disabledTextColor = MaterialTheme.appColors.textPrimary, - backgroundColor = MaterialTheme.appColors.textFieldBackground, + disabledTextColor = MaterialTheme.appColors.textFieldHint, disabledPlaceholderColor = MaterialTheme.appColors.textFieldHint ) } @@ -991,7 +993,7 @@ private fun SelectableField( Text( modifier = Modifier.testTag("txt_placeholder_${name.tagId()}"), text = name, - color = MaterialTheme.appColors.textFieldHint, + color = MaterialTheme.appColors.textFieldText, style = MaterialTheme.appTypography.bodyMedium ) } @@ -1029,8 +1031,10 @@ private fun InputEditField( onValueChanged(it) }, colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = MaterialTheme.appColors.textFieldText, + backgroundColor = MaterialTheme.appColors.textFieldBackground, unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, - backgroundColor = MaterialTheme.appColors.textFieldBackground + cursorColor = MaterialTheme.appColors.textFieldText, ), shape = MaterialTheme.appShapes.textFieldShape, placeholder = { @@ -1116,14 +1120,14 @@ private fun LeaveProfile( OpenEdXButton( text = stringResource(id = R.string.profile_leave), onClick = onLeaveClick, - backgroundColor = MaterialTheme.appColors.warning, + backgroundColor = MaterialTheme.appColors.primary, content = { Text( modifier = Modifier .testTag("txt_leave") .fillMaxWidth(), text = stringResource(id = R.string.profile_leave), - color = MaterialTheme.appColors.textWarning, + color = MaterialTheme.appColors.primaryButtonText, style = MaterialTheme.appTypography.labelLarge, textAlign = TextAlign.Center ) @@ -1131,7 +1135,7 @@ private fun LeaveProfile( ) Spacer(Modifier.height(24.dp)) OpenEdXOutlinedButton( - borderColor = MaterialTheme.appColors.textPrimary, + borderColor = MaterialTheme.appColors.textFieldBorder, textColor = MaterialTheme.appColors.textPrimary, text = stringResource(id = R.string.profile_keep_editing), onClick = onDismissRequest @@ -1208,20 +1212,20 @@ private fun LeaveProfileLandscape( ) { OpenEdXButton( text = stringResource(id = R.string.profile_leave), - backgroundColor = MaterialTheme.appColors.warning, + backgroundColor = MaterialTheme.appColors.primary, content = { AutoSizeText( modifier = Modifier.testTag("txt_leave_profile_dialog_leave"), text = stringResource(id = R.string.profile_leave), style = MaterialTheme.appTypography.bodyMedium, - color = MaterialTheme.appColors.textDark + color = MaterialTheme.appColors.primaryButtonText ) }, onClick = onLeaveClick ) Spacer(Modifier.height(16.dp)) OpenEdXOutlinedButton( - borderColor = MaterialTheme.appColors.textPrimary, + borderColor = MaterialTheme.appColors.textFieldBorder, textColor = MaterialTheme.appColors.textPrimary, text = stringResource(id = R.string.profile_keep_editing), onClick = onDismissRequest, diff --git a/profile/src/main/java/org/openedx/profile/presentation/manageaccount/compose/ManageAccountView.kt b/profile/src/main/java/org/openedx/profile/presentation/manageaccount/compose/ManageAccountView.kt index 42ff5afef..970ff2f91 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/manageaccount/compose/ManageAccountView.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/manageaccount/compose/ManageAccountView.kt @@ -174,7 +174,7 @@ internal fun ManageAccountView( onClick = { onAction(ManageAccountViewAction.EditAccountClick) }, - borderColor = MaterialTheme.appColors.buttonBackground, + borderColor = MaterialTheme.appColors.primaryButtonBackground, textColor = MaterialTheme.appColors.textAccent ) Spacer(modifier = Modifier.height(12.dp)) diff --git a/profile/src/main/java/org/openedx/profile/presentation/profile/compose/ProfileView.kt b/profile/src/main/java/org/openedx/profile/presentation/profile/compose/ProfileView.kt index bec24967f..411ac156d 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/profile/compose/ProfileView.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/profile/compose/ProfileView.kt @@ -149,7 +149,7 @@ internal fun ProfileView( onClick = { onAction(ProfileViewAction.EditAccountClick) }, - borderColor = MaterialTheme.appColors.buttonBackground, + borderColor = MaterialTheme.appColors.primaryButtonBackground, textColor = MaterialTheme.appColors.textAccent ) Spacer(modifier = Modifier.height(12.dp)) diff --git a/whatsnew/src/main/java/org/openedx/whatsnew/presentation/ui/WhatsNewUI.kt b/whatsnew/src/main/java/org/openedx/whatsnew/presentation/ui/WhatsNewUI.kt index a76ff9a10..7d97eee40 100644 --- a/whatsnew/src/main/java/org/openedx/whatsnew/presentation/ui/WhatsNewUI.kt +++ b/whatsnew/src/main/java/org/openedx/whatsnew/presentation/ui/WhatsNewUI.kt @@ -210,7 +210,7 @@ fun NextFinishButton( .testTag("btn_next") .height(42.dp), colors = ButtonDefaults.buttonColors( - backgroundColor = MaterialTheme.appColors.buttonBackground + backgroundColor = MaterialTheme.appColors.primaryButtonBackground ), elevation = null, shape = MaterialTheme.appShapes.navigationButtonShape, @@ -231,14 +231,14 @@ fun NextFinishButton( Text( modifier = Modifier.testTag("txt_next"), text = stringResource(id = R.string.whats_new_navigation_next), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, style = MaterialTheme.appTypography.labelLarge ) Spacer(Modifier.width(8.dp)) Icon( painter = painterResource(id = org.openedx.core.R.drawable.core_ic_forward), contentDescription = null, - tint = MaterialTheme.appColors.buttonText + tint = MaterialTheme.appColors.primaryButtonText ) } } else { @@ -249,14 +249,14 @@ fun NextFinishButton( Text( modifier = Modifier.testTag("txt_done"), text = stringResource(id = R.string.whats_new_navigation_done), - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, style = MaterialTheme.appTypography.labelLarge ) Spacer(Modifier.width(8.dp)) Icon( painter = painterResource(id = org.openedx.core.R.drawable.core_ic_check), contentDescription = null, - tint = MaterialTheme.appColors.buttonText + tint = MaterialTheme.appColors.primaryButtonText ) } } From 0d093ea004e11462c345243935360502c82ac365 Mon Sep 17 00:00:00 2001 From: PavloNetrebchuk <141041606+PavloNetrebchuk@users.noreply.github.com> Date: Wed, 29 May 2024 13:03:12 +0300 Subject: [PATCH 05/38] feat: [FC-0047] Calendar main screen and dialogs (#322) * feat: Created calendar setting screen * feat: CalendarAccessDialog * feat: NewCalendarDialog * fix: Fixes according to PR feedback --- app/src/main/AndroidManifest.xml | 2 + .../main/java/org/openedx/app/AppRouter.kt | 9 +- .../main/java/org/openedx/app/di/AppModule.kt | 2 +- .../java/org/openedx/app/di/ScreenModule.kt | 4 +- .../java/org/openedx/core/config/Config.kt | 5 + .../core/presentation/dialog/DialogUI.kt | 56 +++ .../dialog/appreview/AppReviewUI.kt | 51 +-- .../calendarsync/CalendarSyncDialog.kt | 6 +- .../calendarsync/CalendarSyncDialogType.kt | 44 ++ .../calendarsync/CalendarSyncUIState.kt | 2 +- .../calendarsync/DialogProperties.kt | 2 +- .../{ => video}/VideoQualityFragment.kt | 2 +- .../settings/{ => video}/VideoQualityType.kt | 2 +- .../{ => video}/VideoQualityViewModel.kt | 2 +- .../openedx/core/system}/CalendarManager.kt | 7 +- .../java/org/openedx/core/ui/ComposeCommon.kt | 3 +- .../org/openedx/core/ui/ComposeExtensions.kt | 19 +- core/src/main/res/values/strings.xml | 35 ++ course/src/main/AndroidManifest.xml | 5 - .../course/presentation/CourseRouter.kt | 2 +- .../calendarsync/CalendarSyncDialogType.kt | 45 -- .../container/CourseContainerFragment.kt | 4 +- .../container/CourseContainerViewModel.kt | 15 +- .../presentation/dates/CourseDatesScreen.kt | 6 +- .../dates/CourseDatesViewModel.kt | 6 +- .../outline/CourseOutlineViewModel.kt | 2 +- .../course/presentation/ui/CourseVideosUI.kt | 2 +- course/src/main/res/values/strings.xml | 35 -- .../container/CourseContainerViewModelTest.kt | 2 +- .../dates/CourseDatesViewModelTest.kt | 2 +- .../profile/presentation/ProfileRouter.kt | 4 +- .../calendar/CalendarAccessDialogFragment.kt | 161 ++++++++ .../presentation/calendar/CalendarColor.kt | 19 + .../presentation/calendar/CalendarFragment.kt | 264 ++++++++++++ .../calendar/CalendarViewModel.kt | 14 + .../calendar/NewCalendarDialogFragment.kt | 390 ++++++++++++++++++ .../presentation/settings/SettingsFragment.kt | 11 +- .../presentation/settings/SettingsScreenUI.kt | 66 ++- .../settings/SettingsViewModel.kt | 4 + .../profile/presentation/ui/SettingsUI.kt | 17 +- .../video/VideoSettingsViewModel.kt | 2 +- profile/src/main/res/values/strings.xml | 21 + 42 files changed, 1141 insertions(+), 211 deletions(-) create mode 100644 core/src/main/java/org/openedx/core/presentation/dialog/DialogUI.kt rename {course/src/main/java/org/openedx/course/presentation => core/src/main/java/org/openedx/core/presentation/settings}/calendarsync/CalendarSyncDialog.kt (98%) create mode 100644 core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncDialogType.kt rename {course/src/main/java/org/openedx/course/presentation => core/src/main/java/org/openedx/core/presentation/settings}/calendarsync/CalendarSyncUIState.kt (89%) rename {course/src/main/java/org/openedx/course/presentation => core/src/main/java/org/openedx/core/presentation/settings}/calendarsync/DialogProperties.kt (78%) rename core/src/main/java/org/openedx/core/presentation/settings/{ => video}/VideoQualityFragment.kt (99%) rename core/src/main/java/org/openedx/core/presentation/settings/{ => video}/VideoQualityType.kt (51%) rename core/src/main/java/org/openedx/core/presentation/settings/{ => video}/VideoQualityViewModel.kt (98%) rename {course/src/main/java/org/openedx/course/presentation/calendarsync => core/src/main/java/org/openedx/core/system}/CalendarManager.kt (98%) delete mode 100644 course/src/main/AndroidManifest.xml delete mode 100644 course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncDialogType.kt create mode 100644 profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt create mode 100644 profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarColor.kt create mode 100644 profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarFragment.kt create mode 100644 profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarViewModel.kt create mode 100644 profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8020f6b74..3e8282acb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,8 @@ + + diff --git a/app/src/main/java/org/openedx/app/AppRouter.kt b/app/src/main/java/org/openedx/app/AppRouter.kt index 21f3b5aee..a68b550a2 100644 --- a/app/src/main/java/org/openedx/app/AppRouter.kt +++ b/app/src/main/java/org/openedx/app/AppRouter.kt @@ -13,8 +13,8 @@ import org.openedx.core.presentation.course.CourseViewMode import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRouter import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment import org.openedx.core.presentation.global.webview.WebContentFragment -import org.openedx.core.presentation.settings.VideoQualityFragment -import org.openedx.core.presentation.settings.VideoQualityType +import org.openedx.core.presentation.settings.video.VideoQualityFragment +import org.openedx.core.presentation.settings.video.VideoQualityType import org.openedx.course.presentation.CourseRouter import org.openedx.course.presentation.container.CourseContainerFragment import org.openedx.course.presentation.container.NoAccessCourseContainerFragment @@ -44,6 +44,7 @@ import org.openedx.discussion.presentation.threads.DiscussionThreadsFragment import org.openedx.profile.domain.model.Account import org.openedx.profile.presentation.ProfileRouter import org.openedx.profile.presentation.anothersaccount.AnothersProfileFragment +import org.openedx.profile.presentation.calendar.CalendarFragment import org.openedx.profile.presentation.delete.DeleteProfileFragment import org.openedx.profile.presentation.edit.EditProfileFragment import org.openedx.profile.presentation.manageaccount.ManageAccountFragment @@ -370,6 +371,10 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di override fun navigateToManageAccount(fm: FragmentManager) { replaceFragmentWithBackStack(fm, ManageAccountFragment()) } + + override fun navigateToCalendarSettings(fm: FragmentManager) { + replaceFragmentWithBackStack(fm, CalendarFragment()) + } //endregion private fun replaceFragmentWithBackStack(fm: FragmentManager, fragment: Fragment) { diff --git a/app/src/main/java/org/openedx/app/di/AppModule.kt b/app/src/main/java/org/openedx/app/di/AppModule.kt index 16a30c0c6..529f00ac0 100644 --- a/app/src/main/java/org/openedx/app/di/AppModule.kt +++ b/app/src/main/java/org/openedx/app/di/AppModule.kt @@ -40,6 +40,7 @@ import org.openedx.core.presentation.global.AppData import org.openedx.core.presentation.global.WhatsNewGlobalManager import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRouter import org.openedx.core.system.AppCookieManager +import org.openedx.core.system.CalendarManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.AppUpgradeNotifier @@ -50,7 +51,6 @@ import org.openedx.core.system.notifier.VideoNotifier import org.openedx.course.data.storage.CoursePreferences import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseRouter -import org.openedx.course.presentation.calendarsync.CalendarManager import org.openedx.dashboard.presentation.DashboardAnalytics import org.openedx.dashboard.presentation.DashboardRouter import org.openedx.discovery.presentation.DiscoveryAnalytics diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index c9c395a01..3c99dbc0f 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -13,7 +13,7 @@ import org.openedx.auth.presentation.signin.SignInViewModel import org.openedx.auth.presentation.signup.SignUpViewModel import org.openedx.core.Validator import org.openedx.core.presentation.dialog.selectorbottomsheet.SelectDialogViewModel -import org.openedx.core.presentation.settings.VideoQualityViewModel +import org.openedx.core.presentation.settings.video.VideoQualityViewModel import org.openedx.course.data.repository.CourseRepository import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.container.CourseContainerViewModel @@ -53,6 +53,7 @@ import org.openedx.profile.data.repository.ProfileRepository import org.openedx.profile.domain.interactor.ProfileInteractor import org.openedx.profile.domain.model.Account import org.openedx.profile.presentation.anothersaccount.AnothersProfileViewModel +import org.openedx.profile.presentation.calendar.CalendarViewModel import org.openedx.profile.presentation.delete.DeleteProfileViewModel import org.openedx.profile.presentation.edit.EditProfileViewModel import org.openedx.profile.presentation.manageaccount.ManageAccountViewModel @@ -163,6 +164,7 @@ val screenModule = module { ) } viewModel { ManageAccountViewModel(get(), get(), get(), get(), get()) } + viewModel { CalendarViewModel(get()) } single { CourseRepository(get(), get(), get(), get(), get()) } factory { CourseInteractor(get()) } diff --git a/core/src/main/java/org/openedx/core/config/Config.kt b/core/src/main/java/org/openedx/core/config/Config.kt index 4b40fbc29..b0c3f211d 100644 --- a/core/src/main/java/org/openedx/core/config/Config.kt +++ b/core/src/main/java/org/openedx/core/config/Config.kt @@ -23,6 +23,10 @@ class Config(context: Context) { } } + fun getAppId(): String { + return getString(APPLICATION_ID, "") + } + fun getApiHostURL(): String { return getString(API_HOST_URL, "") } @@ -146,6 +150,7 @@ class Config(context: Context) { } companion object { + private const val APPLICATION_ID = "APPLICATION_ID" private const val API_HOST_URL = "API_HOST_URL" private const val URI_SCHEME = "URI_SCHEME" private const val OAUTH_CLIENT_ID = "OAUTH_CLIENT_ID" diff --git a/core/src/main/java/org/openedx/core/presentation/dialog/DialogUI.kt b/core/src/main/java/org/openedx/core/presentation/dialog/DialogUI.kt new file mode 100644 index 000000000..17b1d2874 --- /dev/null +++ b/core/src/main/java/org/openedx/core/presentation/dialog/DialogUI.kt @@ -0,0 +1,56 @@ +package org.openedx.core.presentation.dialog + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import org.openedx.core.ui.noRippleClickable +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes + +@Composable +fun DefaultDialogBox( + modifier: Modifier = Modifier, + onDismissClick: () -> Unit, + content: @Composable (BoxScope.() -> Unit) +) { + Surface( + modifier = modifier, + color = Color.Transparent + ) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 4.dp) + .noRippleClickable { + onDismissClick() + }, + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .widthIn(max = 640.dp) + .fillMaxWidth() + .clip(MaterialTheme.appShapes.cardShape) + .noRippleClickable {} + .background( + color = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.cardShape + ) + ) { + content.invoke(this) + } + } + } +} diff --git a/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt b/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt index b924cd543..a1df55a05 100644 --- a/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt +++ b/core/src/main/java/org/openedx/core/presentation/dialog/appreview/AppReviewUI.kt @@ -4,26 +4,20 @@ import android.content.res.Configuration.ORIENTATION_LANDSCAPE import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -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.widthIn import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons @@ -40,7 +34,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale @@ -54,7 +47,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.openedx.core.R -import org.openedx.core.ui.noRippleClickable +import org.openedx.core.presentation.dialog.DefaultDialogBox import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appShapes @@ -78,7 +71,7 @@ fun ThankYouDialog( DefaultDialogBox( modifier = modifier, - onDismissClock = onNotNowClick + onDismissClick = onNotNowClick ) { Column( modifier = Modifier @@ -139,7 +132,7 @@ fun FeedbackDialog( DefaultDialogBox( modifier = modifier, - onDismissClock = onNotNowClick + onDismissClick = onNotNowClick ) { Column( modifier = Modifier @@ -210,7 +203,7 @@ fun RateDialog( ) { DefaultDialogBox( modifier = modifier, - onDismissClock = onNotNowClick + onDismissClick = onNotNowClick ) { Column( modifier = Modifier @@ -252,42 +245,6 @@ fun RateDialog( } } -@Composable -fun DefaultDialogBox( - modifier: Modifier = Modifier, - onDismissClock: () -> Unit, - content: @Composable (BoxScope.() -> Unit) -) { - Surface( - modifier = modifier, - color = Color.Transparent - ) { - Box( - modifier = Modifier - .fillMaxSize() - .padding(horizontal = 4.dp) - .noRippleClickable { - onDismissClock() - }, - contentAlignment = Alignment.Center - ) { - Box( - modifier = Modifier - .widthIn(max = 640.dp) - .fillMaxWidth() - .clip(MaterialTheme.appShapes.cardShape) - .noRippleClickable {} - .background( - color = MaterialTheme.appColors.background, - shape = MaterialTheme.appShapes.cardShape - ) - ) { - content.invoke(this) - } - } - } -} - @Composable fun TransparentTextButton( text: String, diff --git a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncDialog.kt b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncDialog.kt similarity index 98% rename from course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncDialog.kt rename to core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncDialog.kt index a3775c99b..ac358228e 100644 --- a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncDialog.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncDialog.kt @@ -1,4 +1,4 @@ -package org.openedx.course.presentation.calendarsync +package org.openedx.core.presentation.settings.calendarsync import android.content.res.Configuration import androidx.compose.foundation.background @@ -23,13 +23,13 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog +import org.openedx.core.R import org.openedx.core.extension.takeIfNotEmpty import org.openedx.core.presentation.global.app_upgrade.TransparentTextButton import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appShapes import org.openedx.core.ui.theme.appTypography -import org.openedx.course.R import androidx.compose.ui.window.DialogProperties as AlertDialogProperties import org.openedx.core.R as CoreR @@ -192,7 +192,7 @@ private fun SyncDialog() { verticalArrangement = Arrangement.spacedBy(8.dp), ) { Text( - text = stringResource(id = R.string.course_title_syncing_calendar), + text = stringResource(id = R.string.core_title_syncing_calendar), color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.titleMedium, maxLines = 2, diff --git a/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncDialogType.kt b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncDialogType.kt new file mode 100644 index 000000000..daab61fa5 --- /dev/null +++ b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncDialogType.kt @@ -0,0 +1,44 @@ +package org.openedx.core.presentation.settings.calendarsync + +import org.openedx.core.R + +enum class CalendarSyncDialogType( + val titleResId: Int = 0, + val messageResId: Int = 0, + val positiveButtonResId: Int = 0, + val negativeButtonResId: Int = 0, +) { + SYNC_DIALOG( + titleResId = R.string.core_title_add_course_calendar, + messageResId = R.string.core_message_add_course_calendar, + positiveButtonResId = R.string.core_ok, + negativeButtonResId = R.string.core_cancel + ), + UN_SYNC_DIALOG( + titleResId = R.string.core_title_remove_course_calendar, + messageResId = R.string.core_message_remove_course_calendar, + positiveButtonResId = R.string.core_label_remove, + negativeButtonResId = R.string.core_cancel + ), + PERMISSION_DIALOG( + titleResId = R.string.core_title_request_calendar_permission, + messageResId = R.string.core_message_request_calendar_permission, + positiveButtonResId = R.string.core_ok, + negativeButtonResId = R.string.core_label_do_not_allow + ), + EVENTS_DIALOG( + messageResId = R.string.core_message_course_calendar_added, + positiveButtonResId = R.string.core_label_view_events, + negativeButtonResId = R.string.core_label_done + ), + OUT_OF_SYNC_DIALOG( + titleResId = R.string.core_title_calendar_out_of_date, + messageResId = R.string.core_message_calendar_out_of_date, + positiveButtonResId = R.string.core_label_update_now, + negativeButtonResId = R.string.core_label_remove_course_calendar, + ), + LOADING_DIALOG( + titleResId = R.string.core_title_syncing_calendar + ), + NONE; +} diff --git a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncUIState.kt b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncUIState.kt similarity index 89% rename from course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncUIState.kt rename to core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncUIState.kt index 24d2212e2..e3062d970 100644 --- a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncUIState.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncUIState.kt @@ -1,4 +1,4 @@ -package org.openedx.course.presentation.calendarsync +package org.openedx.core.presentation.settings.calendarsync import org.openedx.core.domain.model.CourseDateBlock import java.util.concurrent.atomic.AtomicReference diff --git a/course/src/main/java/org/openedx/course/presentation/calendarsync/DialogProperties.kt b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/DialogProperties.kt similarity index 78% rename from course/src/main/java/org/openedx/course/presentation/calendarsync/DialogProperties.kt rename to core/src/main/java/org/openedx/core/presentation/settings/calendarsync/DialogProperties.kt index cefded76c..cfca43193 100644 --- a/course/src/main/java/org/openedx/course/presentation/calendarsync/DialogProperties.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/DialogProperties.kt @@ -1,4 +1,4 @@ -package org.openedx.course.presentation.calendarsync +package org.openedx.core.presentation.settings.calendarsync data class DialogProperties( val title: String, diff --git a/core/src/main/java/org/openedx/core/presentation/settings/VideoQualityFragment.kt b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityFragment.kt similarity index 99% rename from core/src/main/java/org/openedx/core/presentation/settings/VideoQualityFragment.kt rename to core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityFragment.kt index e26d882eb..edd00ce53 100644 --- a/core/src/main/java/org/openedx/core/presentation/settings/VideoQualityFragment.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityFragment.kt @@ -1,4 +1,4 @@ -package org.openedx.core.presentation.settings +package org.openedx.core.presentation.settings.video import android.content.res.Configuration import android.os.Bundle diff --git a/core/src/main/java/org/openedx/core/presentation/settings/VideoQualityType.kt b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityType.kt similarity index 51% rename from core/src/main/java/org/openedx/core/presentation/settings/VideoQualityType.kt rename to core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityType.kt index 4c7973d6a..c39b6d220 100644 --- a/core/src/main/java/org/openedx/core/presentation/settings/VideoQualityType.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityType.kt @@ -1,4 +1,4 @@ -package org.openedx.core.presentation.settings +package org.openedx.core.presentation.settings.video enum class VideoQualityType { Streaming, Download diff --git a/core/src/main/java/org/openedx/core/presentation/settings/VideoQualityViewModel.kt b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityViewModel.kt similarity index 98% rename from core/src/main/java/org/openedx/core/presentation/settings/VideoQualityViewModel.kt rename to core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityViewModel.kt index c6d5176ea..bf30bbe30 100644 --- a/core/src/main/java/org/openedx/core/presentation/settings/VideoQualityViewModel.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityViewModel.kt @@ -1,4 +1,4 @@ -package org.openedx.core.presentation.settings +package org.openedx.core.presentation.settings.video import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData diff --git a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarManager.kt b/core/src/main/java/org/openedx/core/system/CalendarManager.kt similarity index 98% rename from course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarManager.kt rename to core/src/main/java/org/openedx/core/system/CalendarManager.kt index 54639e922..53d7a1e1f 100644 --- a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarManager.kt +++ b/core/src/main/java/org/openedx/core/system/CalendarManager.kt @@ -1,4 +1,4 @@ -package org.openedx.course.presentation.calendarsync +package org.openedx.core.system import android.annotation.SuppressLint import android.content.ContentUris @@ -10,12 +10,11 @@ import android.database.Cursor import android.net.Uri import android.provider.CalendarContract import androidx.core.content.ContextCompat +import org.openedx.core.R import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.CourseDateBlock -import org.openedx.core.system.ResourceManager import org.openedx.core.utils.Logger import org.openedx.core.utils.toCalendar -import org.openedx.course.R import java.util.Calendar import java.util.TimeZone import java.util.concurrent.TimeUnit @@ -165,7 +164,7 @@ class CalendarManager( put(CalendarContract.Events.DTEND, endMillis) put( CalendarContract.Events.TITLE, - "${resourceManager.getString(R.string.course_assignment_due_tag)} : $courseName" + "${resourceManager.getString(R.string.core_assignment_due_tag)} : $courseName" ) put( CalendarContract.Events.DESCRIPTION, diff --git a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt index 212014177..1692e7a4d 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt @@ -939,6 +939,7 @@ fun TextIcon( icon: ImageVector, color: Color, textStyle: TextStyle = MaterialTheme.appTypography.bodySmall, + iconModifier: Modifier = Modifier, onClick: (() -> Unit)? = null, ) { val modifier = if (onClick == null) { @@ -953,7 +954,7 @@ fun TextIcon( ) { Text(text = text, color = color, style = textStyle) Icon( - modifier = Modifier.size((textStyle.fontSize.value + 4).dp), + modifier = iconModifier.size((textStyle.fontSize.value + 4).dp), imageVector = icon, contentDescription = null, tint = color diff --git a/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt b/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt index 6cf198f53..1659a0417 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity @@ -37,6 +38,7 @@ import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.launch @@ -192,4 +194,19 @@ fun Modifier.settingsHeaderBackground(): Modifier = composed { contentScale = ContentScale.FillWidth, alignment = Alignment.TopCenter ) -} \ No newline at end of file +} + +fun Modifier.crop( + horizontal: Dp = 0.dp, + vertical: Dp = 0.dp, +): Modifier = this.layout { measurable, constraints -> + val placeable = measurable.measure(constraints) + fun Dp.toPxInt(): Int = this.toPx().toInt() + + layout( + placeable.width - (horizontal * 2).toPxInt(), + placeable.height - (vertical * 2).toPxInt() + ) { + placeable.placeRelative(-horizontal.toPx().toInt(), -vertical.toPx().toInt()) + } +} diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index ed4b1d99d..668c61935 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -132,6 +132,41 @@ Video download quality Manage Account + Assignment Due + Syncing calendar… + + + Sync to calendar + Automatically sync all deadlines and due dates for this course to your calendar. + + \“%s\” Would Like to Access Your Calendar + %s would like to use your calendar list to subscribe to your personalized %s calendar for this course. + Don’t allow + + Add Course Dates to Calendar + Would you like to add \“%s\” dates to your calendar? \n\nYou can edit or remove your course dates at any time from your calendar or settings. + + \“%s\” has been added to your phone\'s calendar. + View Events + Done + + Remove Course Dates from Calendar + Would you like to remove the \“%s\” dates from your calendar? + Remove + + Your course calendar is out of date + Your course dates have been shifted and your course calendar is no longer up to date with your new schedule. + Update Now + Remove Course Calendar + + Your course calendar has been added. + Your course calendar has been removed. + Your course calendar has been updated. + Error Adding Calendar, Please try later + + + + Home Videos Discussions diff --git a/course/src/main/AndroidManifest.xml b/course/src/main/AndroidManifest.xml deleted file mode 100644 index 5c18ebdbf..000000000 --- a/course/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt b/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt index b2f520679..9b34e7617 100644 --- a/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt +++ b/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt @@ -2,7 +2,7 @@ package org.openedx.course.presentation import androidx.fragment.app.FragmentManager import org.openedx.core.presentation.course.CourseViewMode -import org.openedx.core.presentation.settings.VideoQualityType +import org.openedx.core.presentation.settings.video.VideoQualityType import org.openedx.course.presentation.handouts.HandoutsType interface CourseRouter { diff --git a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncDialogType.kt b/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncDialogType.kt deleted file mode 100644 index 57d6c0dac..000000000 --- a/course/src/main/java/org/openedx/course/presentation/calendarsync/CalendarSyncDialogType.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.openedx.course.presentation.calendarsync - -import org.openedx.course.R -import org.openedx.core.R as CoreR - -enum class CalendarSyncDialogType( - val titleResId: Int = 0, - val messageResId: Int = 0, - val positiveButtonResId: Int = 0, - val negativeButtonResId: Int = 0, -) { - SYNC_DIALOG( - titleResId = R.string.course_title_add_course_calendar, - messageResId = R.string.course_message_add_course_calendar, - positiveButtonResId = CoreR.string.core_ok, - negativeButtonResId = CoreR.string.core_cancel - ), - UN_SYNC_DIALOG( - titleResId = R.string.course_title_remove_course_calendar, - messageResId = R.string.course_message_remove_course_calendar, - positiveButtonResId = R.string.course_label_remove, - negativeButtonResId = CoreR.string.core_cancel - ), - PERMISSION_DIALOG( - titleResId = R.string.course_title_request_calendar_permission, - messageResId = R.string.course_message_request_calendar_permission, - positiveButtonResId = CoreR.string.core_ok, - negativeButtonResId = R.string.course_label_do_not_allow - ), - EVENTS_DIALOG( - messageResId = R.string.course_message_course_calendar_added, - positiveButtonResId = R.string.course_label_view_events, - negativeButtonResId = R.string.course_label_done - ), - OUT_OF_SYNC_DIALOG( - titleResId = R.string.course_title_calendar_out_of_date, - messageResId = R.string.course_message_calendar_out_of_date, - positiveButtonResId = R.string.course_label_update_now, - negativeButtonResId = R.string.course_label_remove_course_calendar, - ), - LOADING_DIALOG( - titleResId = R.string.course_title_syncing_calendar - ), - NONE; -} 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 669b1f661..2d80608ef 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 @@ -55,6 +55,8 @@ import org.koin.core.parameter.parametersOf import org.openedx.core.extension.takeIfNotEmpty import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.presentation.global.viewBinding +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialog +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.OfflineModeDialog import org.openedx.core.ui.RoundTabsBar @@ -65,8 +67,6 @@ import org.openedx.core.ui.theme.appColors import org.openedx.course.DatesShiftedSnackBar import org.openedx.course.R import org.openedx.course.databinding.FragmentCourseContainerBinding -import org.openedx.course.presentation.calendarsync.CalendarSyncDialog -import org.openedx.course.presentation.calendarsync.CalendarSyncDialogType import org.openedx.course.presentation.dates.CourseDatesScreen import org.openedx.course.presentation.handouts.HandoutsScreen import org.openedx.course.presentation.handouts.HandoutsType 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 8562289af..1ec787e54 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 @@ -26,6 +26,9 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.exception.NoCachedDataException import org.openedx.core.extension.isInternetError import org.openedx.core.presentation.course.CourseContainerTab +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncUIState +import org.openedx.core.system.CalendarManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CalendarSyncEvent.CheckCalendarSyncEvent @@ -38,7 +41,6 @@ import org.openedx.core.system.notifier.CourseRefresh import org.openedx.core.system.notifier.CourseStructureUpdated import org.openedx.core.utils.TimeUtils import org.openedx.course.DatesShiftedSnackBar -import org.openedx.course.R import org.openedx.course.data.storage.CoursePreferences import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CalendarSyncDialog @@ -47,9 +49,6 @@ import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseAnalyticsEvent import org.openedx.course.presentation.CourseAnalyticsKey import org.openedx.course.presentation.CourseRouter -import org.openedx.course.presentation.calendarsync.CalendarManager -import org.openedx.course.presentation.calendarsync.CalendarSyncDialogType -import org.openedx.course.presentation.calendarsync.CalendarSyncUIState import java.util.Date import java.util.concurrent.atomic.AtomicReference import org.openedx.core.R as CoreR @@ -283,7 +282,7 @@ class CourseContainerViewModel( val calendarId = getCalendarId() if (calendarId == CalendarManager.CALENDAR_DOES_NOT_EXIST) { - setUiMessage(R.string.course_snackbar_course_calendar_error) + setUiMessage(CoreR.string.core_snackbar_course_calendar_error) setCalendarSyncDialogType(CalendarSyncDialogType.NONE) return @@ -314,10 +313,10 @@ class CourseContainerViewModel( if (updatedEvent) { logCalendarSyncSnackbar(CalendarSyncSnackbar.UPDATED) - setUiMessage(R.string.course_snackbar_course_calendar_updated) + setUiMessage(CoreR.string.core_snackbar_course_calendar_updated) } else if (coursePreferences.isCalendarSyncEventsDialogShown(courseName)) { logCalendarSyncSnackbar(CalendarSyncSnackbar.ADDED) - setUiMessage(R.string.course_snackbar_course_calendar_added) + setUiMessage(CoreR.string.core_snackbar_course_calendar_added) } else { coursePreferences.setCalendarSyncEventsDialogShown(courseName) setCalendarSyncDialogType(CalendarSyncDialogType.EVENTS_DIALOG) @@ -361,7 +360,7 @@ class CourseContainerViewModel( } logCalendarSyncSnackbar(CalendarSyncSnackbar.REMOVED) - setUiMessage(R.string.course_snackbar_course_calendar_removed) + setUiMessage(CoreR.string.core_snackbar_course_calendar_removed) } } diff --git a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt index 715584497..6e875d263 100644 --- a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt @@ -73,6 +73,7 @@ import org.openedx.core.extension.isNotEmptyThenLet import org.openedx.core.presentation.CoreAnalyticsScreen import org.openedx.core.presentation.course.CourseViewMode import org.openedx.core.presentation.dialog.alert.ActionDialogFragment +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncUIState import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType @@ -86,7 +87,6 @@ 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.calendarsync.CalendarSyncUIState import org.openedx.course.presentation.ui.CourseDatesBanner import org.openedx.course.presentation.ui.CourseDatesBannerTablet import java.util.concurrent.atomic.AtomicReference @@ -354,7 +354,7 @@ fun CalendarSyncCard( modifier = Modifier .padding(start = 8.dp, end = 8.dp) .weight(1f), - text = stringResource(id = R.string.course_header_sync_to_calendar), + text = stringResource(id = CoreR.string.core_header_sync_to_calendar), style = MaterialTheme.appTypography.titleMedium, color = MaterialTheme.appColors.textDark ) @@ -374,7 +374,7 @@ fun CalendarSyncCard( .fillMaxWidth() .padding(top = 8.dp) .height(40.dp), - text = stringResource(id = R.string.course_body_sync_to_calendar), + text = stringResource(id = CoreR.string.core_body_sync_to_calendar), style = MaterialTheme.appTypography.bodyMedium, color = MaterialTheme.appColors.textDark, ) 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 e5ce08ed7..5d7f94d47 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 @@ -23,6 +23,9 @@ import org.openedx.core.domain.model.CourseStructure import org.openedx.core.extension.getSequentialBlocks import org.openedx.core.extension.getVerticalBlocks import org.openedx.core.extension.isInternetError +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncUIState +import org.openedx.core.system.CalendarManager import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CalendarSyncEvent.CheckCalendarSyncEvent @@ -35,9 +38,6 @@ import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseAnalyticsEvent import org.openedx.course.presentation.CourseAnalyticsKey -import org.openedx.course.presentation.calendarsync.CalendarManager -import org.openedx.course.presentation.calendarsync.CalendarSyncDialogType -import org.openedx.course.presentation.calendarsync.CalendarSyncUIState import org.openedx.core.R as CoreR class CourseDatesViewModel( 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 7a6e08b58..306498d89 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 @@ -25,6 +25,7 @@ import org.openedx.core.module.DownloadWorkerController import org.openedx.core.module.db.DownloadDao import org.openedx.core.module.download.BaseDownloadViewModel import org.openedx.core.presentation.CoreAnalytics +import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent @@ -36,7 +37,6 @@ import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseAnalyticsEvent import org.openedx.course.presentation.CourseAnalyticsKey -import org.openedx.course.presentation.calendarsync.CalendarSyncDialogType import org.openedx.course.R as courseR class CourseOutlineViewModel( diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt index 16fd90992..30706cd6d 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt @@ -67,7 +67,7 @@ import org.openedx.core.domain.model.VideoSettings import org.openedx.core.extension.toFileSize import org.openedx.core.module.download.DownloadModelsSize import org.openedx.core.presentation.course.CourseViewMode -import org.openedx.core.presentation.settings.VideoQualityType +import org.openedx.core.presentation.settings.video.VideoQualityType import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType diff --git a/course/src/main/res/values/strings.xml b/course/src/main/res/values/strings.xml index 802065471..6a974cb15 100644 --- a/course/src/main/res/values/strings.xml +++ b/course/src/main/res/values/strings.xml @@ -41,41 +41,6 @@ Course dates are not currently available. - - Sync to calendar - Automatically sync all deadlines and due dates for this course to your calendar. - - \“%s\” Would Like to Access Your Calendar - %s would like to use your calendar list to subscribe to your personalized %s calendar for this course. - Don’t allow - - Add Course Dates to Calendar - Would you like to add \“%s\” dates to your calendar? \n\nYou can edit or remove your course dates at any time from your calendar or settings. - - Syncing calendar… - - \“%s\” has been added to your phone\'s calendar. - View Events - Done - - Remove Course Dates from Calendar - Would you like to remove the \“%s\” dates from your calendar? - Remove - - Your course calendar is out of date - Your course dates have been shifted and your course calendar is no longer up to date with your new schedule. - Update Now - Remove Course Calendar - - Your course calendar has been added. - Your course calendar has been removed. - Your course calendar has been updated. - Error Adding Calendar, Please try later - - Assignment Due - - - Video player Remove course section diff --git a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt index 1b2cb6cca..aff60b21e 100644 --- a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt @@ -33,6 +33,7 @@ import org.openedx.core.domain.model.AppConfig import org.openedx.core.domain.model.CourseDatesCalendarSync import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.system.CalendarManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CourseNotifier @@ -42,7 +43,6 @@ import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseAnalyticsEvent import org.openedx.course.presentation.CourseRouter -import org.openedx.course.presentation.calendarsync.CalendarManager import java.net.UnknownHostException import java.util.Date diff --git a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt index 13e78fe91..f8715e7b3 100644 --- a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt @@ -37,13 +37,13 @@ import org.openedx.core.domain.model.CourseDatesResult import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.DatesSection +import org.openedx.core.system.CalendarManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics -import org.openedx.course.presentation.calendarsync.CalendarManager import java.net.UnknownHostException import java.util.Date diff --git a/profile/src/main/java/org/openedx/profile/presentation/ProfileRouter.kt b/profile/src/main/java/org/openedx/profile/presentation/ProfileRouter.kt index a4b194de4..fd7514bd5 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/ProfileRouter.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/ProfileRouter.kt @@ -1,7 +1,7 @@ package org.openedx.profile.presentation import androidx.fragment.app.FragmentManager -import org.openedx.core.presentation.settings.VideoQualityType +import org.openedx.core.presentation.settings.video.VideoQualityType import org.openedx.profile.domain.model.Account interface ProfileRouter { @@ -21,4 +21,6 @@ interface ProfileRouter { fun navigateToWebContent(fm: FragmentManager, title: String, url: String) fun navigateToManageAccount(fm: FragmentManager) + + fun navigateToCalendarSettings(fm: FragmentManager) } diff --git a/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt new file mode 100644 index 000000000..a9094c67d --- /dev/null +++ b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt @@ -0,0 +1,161 @@ +package org.openedx.profile.presentation.calendar + +import android.content.Intent +import android.content.res.Configuration +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.net.Uri +import android.os.Bundle +import android.provider.Settings +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.OpenInNew +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.fragment.app.DialogFragment +import org.koin.android.ext.android.inject +import org.openedx.core.config.Config +import org.openedx.core.presentation.dialog.DefaultDialogBox +import org.openedx.core.ui.OpenEdXButton +import org.openedx.core.ui.OpenEdXOutlinedButton +import org.openedx.core.ui.TextIcon +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appTypography +import org.openedx.profile.R +import org.openedx.core.R as CoreR + +class CalendarAccessDialogFragment : DialogFragment() { + + private val config by inject() + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ) = ComposeView(requireContext()).apply { + dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + OpenEdXTheme { + CalendarAccessDialog( + onCancelClick = { + dismiss() + }, + onGrantCalendarAccessClick = { + val intent = Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.parse("package:" + config.getAppId()) + ) + startActivity(intent) + dismiss() + } + ) + } + } + } + + companion object { + const val DIALOG_TAG = "CalendarAccessDialogFragment" + + fun newInstance(): CalendarAccessDialogFragment { + return CalendarAccessDialogFragment() + } + } +} + +@Composable +private fun CalendarAccessDialog( + modifier: Modifier = Modifier, + onCancelClick: () -> Unit, + onGrantCalendarAccessClick: () -> Unit +) { + DefaultDialogBox( + modifier = modifier, + onDismissClick = onCancelClick + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Image( + modifier = Modifier.size(24.dp), + painter = painterResource(id = CoreR.drawable.core_ic_warning), + contentDescription = null + ) + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.profile_calendar_access_dialog_title), + style = MaterialTheme.appTypography.titleLarge, + color = MaterialTheme.appColors.textDark + ) + } + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.profile_calendar_access_dialog_description), + style = MaterialTheme.appTypography.bodyMedium, + color = MaterialTheme.appColors.textDark + ) + OpenEdXButton( + modifier = Modifier.fillMaxWidth(), + onClick = { + onGrantCalendarAccessClick() + }, + content = { + TextIcon( + text = stringResource(id = R.string.profile_grant_access_calendar), + icon = Icons.AutoMirrored.Filled.OpenInNew, + color = MaterialTheme.appColors.buttonText, + textStyle = MaterialTheme.appTypography.labelLarge, + iconModifier = Modifier.padding(start = 4.dp) + ) + } + ) + OpenEdXOutlinedButton( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = CoreR.string.core_cancel), + backgroundColor = MaterialTheme.appColors.background, + borderColor = MaterialTheme.appColors.buttonBackground, + textColor = MaterialTheme.appColors.buttonBackground, + onClick = { + onCancelClick() + } + ) + } + } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun CalendarAccessDialogPreview() { + OpenEdXTheme { + CalendarAccessDialog( + onCancelClick = { }, + onGrantCalendarAccessClick = { } + ) + } +} diff --git a/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarColor.kt b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarColor.kt new file mode 100644 index 000000000..361fa5776 --- /dev/null +++ b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarColor.kt @@ -0,0 +1,19 @@ +package org.openedx.profile.presentation.calendar + +import androidx.annotation.StringRes +import org.openedx.profile.R + +enum class CalendarColor( + @StringRes + val title: Int, + val color: Long +) { + ACCENT(R.string.calendar_color_accent, 0xFFD13329), + RED(R.string.calendar_color_red, 0xFFFF2967), + ORANGE(R.string.calendar_color_orange, 0xFFFF9501), + YELLOW(R.string.calendar_color_yellow, 0xFFFFCC01), + GREEN(R.string.calendar_color_green, 0xFF64DA38), + BLUE(R.string.calendar_color_blue, 0xFF1AAEF8), + PURPLE(R.string.calendar_color_purple, 0xFFCC73E1), + BROWN(R.string.calendar_color_brown, 0xFFA2845E); +} diff --git a/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarFragment.kt new file mode 100644 index 000000000..8a8794c94 --- /dev/null +++ b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarFragment.kt @@ -0,0 +1,264 @@ +package org.openedx.profile.presentation.calendar + +import android.content.res.Configuration +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +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.widthIn +import androidx.compose.material.Card +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Autorenew +import androidx.compose.material.icons.rounded.CalendarToday +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTagsAsResourceId +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.fragment.app.Fragment +import org.koin.androidx.viewmodel.ext.android.viewModel +import org.openedx.core.ui.OpenEdXButton +import org.openedx.core.ui.Toolbar +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.settingsHeaderBackground +import org.openedx.core.ui.statusBarsInset +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes +import org.openedx.core.ui.theme.appTypography +import org.openedx.core.ui.windowSizeValue +import org.openedx.profile.R +import org.openedx.core.R as CoreR + +class CalendarFragment : Fragment() { + + private val viewModel by viewModel() + + private val permissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestMultiplePermissions() + ) { isGranted -> + if (!isGranted.containsValue(false)) { + val dialog = NewCalendarDialogFragment.newInstance() + dialog.show( + requireActivity().supportFragmentManager, + NewCalendarDialogFragment.DIALOG_TAG + ) + } else { + val dialog = CalendarAccessDialogFragment.newInstance() + dialog.show( + requireActivity().supportFragmentManager, + CalendarAccessDialogFragment.DIALOG_TAG + ) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ) = ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + OpenEdXTheme { + val windowSize = rememberWindowSize() + + CalendarScreen( + windowSize = windowSize, + setUpCalendarSync = { + viewModel.setUpCalendarSync(permissionLauncher) + }, + onBackClick = { + requireActivity().supportFragmentManager.popBackStack() + } + ) + } + } + } +} + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +private fun CalendarScreen( + windowSize: WindowSize, + setUpCalendarSync: () -> Unit, + onBackClick: () -> Unit +) { + val scaffoldState = rememberScaffoldState() + + Scaffold( + modifier = Modifier + .fillMaxSize() + .semantics { + testTagsAsResourceId = true + }, + scaffoldState = scaffoldState + ) { paddingValues -> + + val contentWidth by remember(key1 = windowSize) { + mutableStateOf( + windowSize.windowSizeValue( + expanded = Modifier.widthIn(Dp.Unspecified, 420.dp), + compact = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + ) + ) + } + + val topBarWidth by remember(key1 = windowSize) { + mutableStateOf( + windowSize.windowSizeValue( + expanded = Modifier.widthIn(Dp.Unspecified, 560.dp), + compact = Modifier + .fillMaxWidth() + ) + ) + } + + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.TopCenter + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .settingsHeaderBackground() + .statusBarsInset(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Toolbar( + modifier = topBarWidth + .displayCutoutForLandscape(), + label = stringResource(id = R.string.profile_dates_and_calendar), + canShowBackBtn = true, + labelTint = MaterialTheme.appColors.settingsTitleContent, + iconTint = MaterialTheme.appColors.settingsTitleContent, + onBackClick = onBackClick + ) + + Box( + modifier = Modifier + .fillMaxSize() + .clip(MaterialTheme.appShapes.screenBackgroundShape) + .background(MaterialTheme.appColors.background) + .displayCutoutForLandscape(), + contentAlignment = Alignment.TopCenter + ) { + Column( + modifier = contentWidth.padding(vertical = 28.dp), + ) { + Text( + modifier = Modifier.testTag("txt_settings"), + text = stringResource(id = CoreR.string.core_settings), + style = MaterialTheme.appTypography.labelLarge, + color = MaterialTheme.appColors.textSecondary + ) + Spacer(modifier = Modifier.height(14.dp)) + Card( + shape = MaterialTheme.appShapes.cardShape, + elevation = 0.dp, + backgroundColor = MaterialTheme.appColors.cardViewBackground + ) { + Column( + modifier = Modifier + .padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .padding(vertical = 28.dp), + contentAlignment = Alignment.Center + ) { + Icon( + modifier = Modifier + .fillMaxWidth() + .height(148.dp), + tint = MaterialTheme.appColors.textDark, + imageVector = Icons.Rounded.CalendarToday, + contentDescription = null + ) + Icon( + modifier = Modifier + .fillMaxWidth() + .padding(top = 30.dp) + .height(60.dp), + tint = MaterialTheme.appColors.textDark, + imageVector = Icons.Default.Autorenew, + contentDescription = null + ) + } + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + text = stringResource(id = R.string.profile_calendar_sync), + style = MaterialTheme.appTypography.titleMedium, + color = MaterialTheme.appColors.textDark + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + text = stringResource(id = R.string.profile_calendar_sync_description), + style = MaterialTheme.appTypography.labelLarge, + color = MaterialTheme.appColors.textDark + ) + Spacer(modifier = Modifier.height(16.dp)) + OpenEdXButton( + modifier = Modifier.fillMaxWidth(0.75f), + text = stringResource(id = R.string.profile_set_up_calendar_sync), + onClick = { + setUpCalendarSync() + } + ) + Spacer(modifier = Modifier.height(24.dp)) + } + } + } + } + } + } + } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun CalendarScreenPreview() { + OpenEdXTheme { + CalendarScreen( + windowSize = WindowSize(WindowType.Compact, WindowType.Compact), + setUpCalendarSync = {}, + onBackClick = {} + ) + } +} diff --git a/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarViewModel.kt b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarViewModel.kt new file mode 100644 index 000000000..316b689b4 --- /dev/null +++ b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarViewModel.kt @@ -0,0 +1,14 @@ +package org.openedx.profile.presentation.calendar + +import androidx.activity.result.ActivityResultLauncher +import org.openedx.core.BaseViewModel +import org.openedx.core.system.CalendarManager + +class CalendarViewModel( + private val calendarManager: CalendarManager +) : BaseViewModel() { + + fun setUpCalendarSync(permissionLauncher: ActivityResultLauncher>) { + permissionLauncher.launch(calendarManager.permissions) + } +} diff --git a/profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt new file mode 100644 index 000000000..bfd453f5c --- /dev/null +++ b/profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt @@ -0,0 +1,390 @@ +package org.openedx.profile.presentation.calendar + +import android.content.Context +import android.content.res.Configuration +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.shape.CircleShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Divider +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.material.TextFieldDefaults +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.ExpandMore +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +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.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.fragment.app.DialogFragment +import org.openedx.core.presentation.dialog.DefaultDialogBox +import org.openedx.core.ui.OpenEdXButton +import org.openedx.core.ui.OpenEdXOutlinedButton +import org.openedx.core.ui.crop +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes +import org.openedx.core.ui.theme.appTypography +import org.openedx.profile.R +import androidx.compose.ui.graphics.Color as ComposeColor +import org.openedx.core.R as CoreR + +class NewCalendarDialogFragment : DialogFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ) = ComposeView(requireContext()).apply { + dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + OpenEdXTheme { + NewCalendarDialog( + onCancelClick = { + dismiss() + }, + onBeginSyncingClick = { calendarName, calendarColor -> + //TODO Create calendar and sync events + } + ) + } + } + } + + companion object { + const val DIALOG_TAG = "NewCalendarDialogFragment" + + fun newInstance(): NewCalendarDialogFragment { + return NewCalendarDialogFragment() + } + + fun getDefaultCalendarName(context: Context): String { + return "${context.getString(CoreR.string.app_name)} ${context.getString(R.string.profile_course_dates)}" + } + } +} + +@Composable +private fun NewCalendarDialog( + modifier: Modifier = Modifier, + onCancelClick: () -> Unit, + onBeginSyncingClick: (calendarName: String, calendarColor: CalendarColor) -> Unit +) { + val context = LocalContext.current + var calendarName by rememberSaveable { + mutableStateOf("") + } + var calendarColor by rememberSaveable { + mutableStateOf(CalendarColor.ACCENT) + } + DefaultDialogBox( + modifier = modifier, + onDismissClick = onCancelClick + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1f), + text = stringResource(id = R.string.profile_new_calendar), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.titleLarge + ) + Icon( + modifier = Modifier + .size(24.dp) + .clickable { + onCancelClick() + }, + imageVector = Icons.Default.Close, + contentDescription = null, + tint = MaterialTheme.appColors.primary + ) + } + CalendarNameTextField( + onValueChanged = { + calendarName = it + } + ) + ColorDropdown( + onValueChanged = { + calendarColor = it + } + ) + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.profile_new_calendar_description), + style = MaterialTheme.appTypography.bodyMedium, + textAlign = TextAlign.Center, + color = MaterialTheme.appColors.textDark + ) + OpenEdXOutlinedButton( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = CoreR.string.core_cancel), + backgroundColor = MaterialTheme.appColors.background, + borderColor = MaterialTheme.appColors.buttonBackground, + textColor = MaterialTheme.appColors.buttonBackground, + onClick = { + onCancelClick() + } + ) + OpenEdXButton( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.profile_begin_syncing), + onClick = { + onBeginSyncingClick( + calendarName.ifEmpty { NewCalendarDialogFragment.getDefaultCalendarName(context) }, + calendarColor + ) + } + ) + } + } +} + +@Composable +private fun CalendarNameTextField( + modifier: Modifier = Modifier, + onValueChanged: (String) -> Unit +) { + val focusManager = LocalFocusManager.current + var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) { + mutableStateOf( + TextFieldValue("") + ) + } + + Column { + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.profile_calendar_name), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.labelLarge + ) + Spacer(modifier = Modifier.height(8.dp)) + OutlinedTextField( + modifier = modifier + .fillMaxWidth() + .height(48.dp), + value = textFieldValue, + onValueChange = { + textFieldValue = it + onValueChanged(it.text.trim()) + }, + colors = TextFieldDefaults.outlinedTextFieldColors( + unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder + ), + shape = MaterialTheme.appShapes.textFieldShape, + placeholder = { + Text( + text = NewCalendarDialogFragment.getDefaultCalendarName(LocalContext.current), + color = MaterialTheme.appColors.textFieldHint, + style = MaterialTheme.appTypography.bodyMedium + ) + }, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Next + ), + keyboardActions = KeyboardActions { + focusManager.clearFocus() + }, + textStyle = MaterialTheme.appTypography.bodyMedium, + singleLine = true + ) + } +} + +@Composable +private fun ColorDropdown( + modifier: Modifier = Modifier, + onValueChanged: (CalendarColor) -> Unit +) { + val density = LocalDensity.current + var expanded by remember { mutableStateOf(false) } + var currentValue by remember { mutableStateOf(CalendarColor.ACCENT) } + var dropdownWidth by remember { mutableStateOf(300.dp) } + val colorArrowRotation by animateFloatAsState( + targetValue = if (expanded) 180f else 0f, + label = "" + ) + + Column( + modifier = modifier + ) { + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.profile_color), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.labelLarge + ) + Spacer(modifier = Modifier.height(8.dp)) + Row( + modifier = Modifier + .fillMaxWidth() + .height(48.dp) + .clip(MaterialTheme.appShapes.textFieldShape) + .border( + 1.dp, + MaterialTheme.appColors.textFieldBorder, + MaterialTheme.appShapes.textFieldShape + ) + .onSizeChanged { + dropdownWidth = with(density) { it.width.toDp() } + } + .clickable { + expanded = true + }, + verticalAlignment = Alignment.CenterVertically + ) { + ColorCircle( + modifier = Modifier + .padding(start = 16.dp), + color = ComposeColor(currentValue.color) + ) + Text( + modifier = Modifier + .weight(1f) + .padding(horizontal = 8.dp), + text = stringResource(id = currentValue.title), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.bodyMedium + ) + Icon( + modifier = Modifier + .padding(end = 16.dp) + .rotate(colorArrowRotation), + imageVector = Icons.Default.ExpandMore, + tint = MaterialTheme.appColors.textDark, + contentDescription = null + ) + } + + MaterialTheme( + colors = MaterialTheme.colors.copy(surface = MaterialTheme.appColors.background), + shapes = MaterialTheme.shapes.copy(MaterialTheme.appShapes.textFieldShape) + ) { + Spacer(modifier = Modifier.padding(top = 4.dp)) + DropdownMenu( + modifier = Modifier + .crop(vertical = 8.dp) + .height(240.dp) + .width(dropdownWidth) + .border( + 1.dp, + MaterialTheme.appColors.textFieldBorder, + MaterialTheme.appShapes.textFieldShape + ) + .crop(vertical = 8.dp), + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + for ((index, calendarColor) in CalendarColor.entries.withIndex()) { + DropdownMenuItem( + modifier = Modifier + .background(MaterialTheme.appColors.background), + onClick = { + currentValue = calendarColor + expanded = false + onValueChanged(CalendarColor.entries[index]) + } + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + ColorCircle( + color = ComposeColor(calendarColor.color) + ) + Text( + text = stringResource(id = calendarColor.title), + style = MaterialTheme.appTypography.titleSmall, + color = MaterialTheme.appColors.textDark + ) + } + } + if (index < CalendarColor.entries.lastIndex) { + Divider( + modifier = Modifier.padding(horizontal = 16.dp), + color = MaterialTheme.appColors.divider + ) + } + } + } + } + } +} + +@Composable +private fun ColorCircle( + modifier: Modifier = Modifier, + color: ComposeColor +) { + Box( + modifier = modifier + .size(18.dp) + .clip(CircleShape) + .background(color) + ) +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun NewCalendarDialogPreview() { + OpenEdXTheme { + NewCalendarDialog( + onCancelClick = { }, + onBeginSyncingClick = { _, _ -> } + ) + } +} diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt index fbdd0b4af..7ac402330 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt @@ -83,11 +83,17 @@ class SettingsFragment : Fragment() { ) } - SettingsScreenAction.ManageAccount -> { + SettingsScreenAction.ManageAccountClick -> { viewModel.manageAccountClicked( requireActivity().supportFragmentManager ) } + + SettingsScreenAction.CalendarSettingsClick -> { + viewModel.calendarSettingsClicked( + requireActivity().supportFragmentManager + ) + } } } ) @@ -112,6 +118,7 @@ internal interface SettingsScreenAction { object TermsClick : SettingsScreenAction object SupportClick : SettingsScreenAction object VideoSettingsClick : SettingsScreenAction - object ManageAccount : SettingsScreenAction + object ManageAccountClick : SettingsScreenAction + object CalendarSettingsClick : SettingsScreenAction } diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt index f5c0a7bc5..419172232 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt @@ -21,7 +21,6 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.Card import androidx.compose.material.CircularProgressIndicator -import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme @@ -68,6 +67,7 @@ import org.openedx.core.ui.theme.appShapes import org.openedx.core.ui.theme.appTypography import org.openedx.core.ui.windowSizeValue import org.openedx.profile.domain.model.Configuration +import org.openedx.profile.presentation.ui.SettingsDivider import org.openedx.profile.presentation.ui.SettingsItem import org.openedx.profile.R as profileR @@ -170,14 +170,19 @@ internal fun SettingsScreen( Spacer(Modifier.height(30.dp)) ManageAccountSection(onManageAccountClick = { - onAction(SettingsScreenAction.ManageAccount) + onAction(SettingsScreenAction.ManageAccountClick) }) Spacer(modifier = Modifier.height(24.dp)) - SettingsSection(onVideoSettingsClick = { - onAction(SettingsScreenAction.VideoSettingsClick) - }) + SettingsSection( + onVideoSettingsClick = { + onAction(SettingsScreenAction.VideoSettingsClick) + }, + onCalendarSettingsClick = { + onAction(SettingsScreenAction.CalendarSettingsClick) + } + ) Spacer(modifier = Modifier.height(24.dp)) @@ -205,7 +210,10 @@ internal fun SettingsScreen( } @Composable -private fun SettingsSection(onVideoSettingsClick: () -> Unit) { +private fun SettingsSection( + onVideoSettingsClick: () -> Unit, + onCalendarSettingsClick: () -> Unit +) { Column { Text( modifier = Modifier.testTag("txt_settings"), @@ -225,6 +233,11 @@ private fun SettingsSection(onVideoSettingsClick: () -> Unit) { text = stringResource(id = profileR.string.profile_video), onClick = onVideoSettingsClick ) + SettingsDivider() + SettingsItem( + text = stringResource(id = profileR.string.profile_dates_and_calendar), + onClick = onCalendarSettingsClick + ) } } } @@ -273,46 +286,31 @@ private fun SupportInfoSection( SettingsItem(text = stringResource(id = profileR.string.profile_contact_support)) { onAction(SettingsScreenAction.SupportClick) } - Divider( - modifier = Modifier.padding(vertical = 4.dp), - color = MaterialTheme.appColors.divider - ) + SettingsDivider() } if (uiState.configuration.agreementUrls.tosUrl.isNotBlank()) { SettingsItem(text = stringResource(id = R.string.core_terms_of_use)) { onAction(SettingsScreenAction.TermsClick) } - Divider( - modifier = Modifier.padding(vertical = 4.dp), - color = MaterialTheme.appColors.divider - ) + SettingsDivider() } if (uiState.configuration.agreementUrls.privacyPolicyUrl.isNotBlank()) { SettingsItem(text = stringResource(id = R.string.core_privacy_policy)) { onAction(SettingsScreenAction.PrivacyPolicyClick) } - Divider( - modifier = Modifier.padding(vertical = 4.dp), - color = MaterialTheme.appColors.divider - ) + SettingsDivider() } if (uiState.configuration.agreementUrls.cookiePolicyUrl.isNotBlank()) { SettingsItem(text = stringResource(id = R.string.core_cookie_policy)) { onAction(SettingsScreenAction.CookiePolicyClick) } - Divider( - modifier = Modifier.padding(vertical = 4.dp), - color = MaterialTheme.appColors.divider - ) + SettingsDivider() } if (uiState.configuration.agreementUrls.dataSellConsentUrl.isNotBlank()) { SettingsItem(text = stringResource(id = R.string.core_data_sell)) { onAction(SettingsScreenAction.DataSellClick) } - Divider( - modifier = Modifier.padding(vertical = 4.dp), - color = MaterialTheme.appColors.divider - ) + SettingsDivider() } if (uiState.configuration.faqUrl.isNotBlank()) { val uriHandler = LocalUriHandler.current @@ -323,10 +321,7 @@ private fun SupportInfoSection( uriHandler.openUri(uiState.configuration.faqUrl) onAction(SettingsScreenAction.FaqClick) } - Divider( - modifier = Modifier.padding(vertical = 4.dp), - color = MaterialTheme.appColors.divider - ) + SettingsDivider() } AppVersionItem( versionName = uiState.configuration.versionName, @@ -344,16 +339,17 @@ private fun LogoutButton(onClick: () -> Unit) { Card( modifier = Modifier .testTag("btn_logout") - .fillMaxWidth() - .clickable { - onClick() - }, + .fillMaxWidth(), shape = MaterialTheme.appShapes.cardShape, elevation = 0.dp, backgroundColor = MaterialTheme.appColors.cardViewBackground ) { Row( - modifier = Modifier.padding(20.dp), + modifier = Modifier + .clickable { + onClick() + } + .padding(20.dp), horizontalArrangement = Arrangement.SpaceBetween ) { Text( diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt index 2c7471ebd..9715eb774 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt @@ -185,6 +185,10 @@ class SettingsViewModel( router.navigateToManageAccount(fragmentManager) } + fun calendarSettingsClicked(fragmentManager: FragmentManager) { + router.navigateToCalendarSettings(fragmentManager) + } + fun restartApp(fragmentManager: FragmentManager) { router.restartApp( fragmentManager, diff --git a/profile/src/main/java/org/openedx/profile/presentation/ui/SettingsUI.kt b/profile/src/main/java/org/openedx/profile/presentation/ui/SettingsUI.kt index 6960a0864..df6c719ca 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/ui/SettingsUI.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/ui/SettingsUI.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -38,7 +39,10 @@ fun SettingsItem( .testTag("btn_${text.tagId()}") .fillMaxWidth() .clickable { onClick() } - .padding(20.dp), + .padding( + vertical = 24.dp, + horizontal = 20.dp + ), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { @@ -59,3 +63,14 @@ fun SettingsItem( ) } } + +@Composable +fun SettingsDivider() { + Divider( + modifier = Modifier + .padding( + horizontal = 20.dp + ), + color = MaterialTheme.appColors.divider + ) +} diff --git a/profile/src/main/java/org/openedx/profile/presentation/video/VideoSettingsViewModel.kt b/profile/src/main/java/org/openedx/profile/presentation/video/VideoSettingsViewModel.kt index b98ec8709..f0ed7622a 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/video/VideoSettingsViewModel.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/video/VideoSettingsViewModel.kt @@ -10,7 +10,7 @@ import kotlinx.coroutines.launch import org.openedx.core.BaseViewModel import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.VideoSettings -import org.openedx.core.presentation.settings.VideoQualityType +import org.openedx.core.presentation.settings.video.VideoQualityType import org.openedx.core.system.notifier.VideoNotifier import org.openedx.core.system.notifier.VideoQualityChanged import org.openedx.profile.presentation.ProfileAnalytics diff --git a/profile/src/main/res/values/strings.xml b/profile/src/main/res/values/strings.xml index efdb04c30..60f0e4060 100644 --- a/profile/src/main/res/values/strings.xml +++ b/profile/src/main/res/values/strings.xml @@ -37,7 +37,28 @@ Contact Support Support Video + Dates & Calendar Wi-fi only download Only download content when wi-fi is turned on + Calendar Sync + Set up calendar sync to show your upcoming assignments and course milestones on your calendar. New assignments and shifted course dates will sync automatically + Set Up Calendar Sync + Calendar Access + To show upcoming assignments and course milestones on your calendar, we need permission to access your calendar. + Grant Calendar Access + New Calendar + Upcoming assignments for active courses will appear on this calendar + Begin Syncing + Calendar Name + Red + Orange + Yellow + Green + Blue + Purple + Brown + Accent + Course Dates + Color From c2684f9aa6be7048316eb0222bd6f3b671854393 Mon Sep 17 00:00:00 2001 From: PavloNetrebchuk <141041606+PavloNetrebchuk@users.noreply.github.com> Date: Thu, 30 May 2024 11:11:05 +0300 Subject: [PATCH 06/38] feat: [FC-0047] Improved Dashboard Level Navigation (#308) * feat: Created Learn screen. Added course/program navigation. Added endpoint for UserCourses screen. * feat: Added primary course card * feat: Added start/resume course button * feat: Added alignment items * feat: Fix future assignment date, add courses list, add onSearch and onCourse clicks * feat: Add feature flag for enabling new/old dashboard screen, add UserCoursesScreen onClick methods * feat: Create AllEnrolledCoursesFragment. Add endpoint parameters * feat: AllEnrolledCoursesFragment UI * feat: Minor code refactoring, show cached data if no internet connection * feat: UserCourses screen data caching * feat: Dashboard * refactor: Dashboard type flag change, start course button change * feat: Added programs fragment to LearnFragment viewPager * feat: Empty states and settings button * fix: Number of courses * fix: Minor UI changes * fix: Fixes according to designer feedback * fix: Fixes after demo * refactor: Move CourseContainerTab * fix: Fixes according to PR feedback * fix: Fixes according to PR feedback * feat: added a patch from Omer Habib * fix: Fixes according to PR feedback --- .../main/java/org/openedx/app/AppRouter.kt | 25 +- .../org/openedx/app/InDevelopmentFragment.kt | 56 -- .../main/java/org/openedx/app/MainFragment.kt | 42 +- .../java/org/openedx/app/MainViewModel.kt | 18 +- .../main/java/org/openedx/app/di/AppModule.kt | 3 + .../java/org/openedx/app/di/ScreenModule.kt | 18 +- app/src/main/res/color/bottom_nav_color.xml | 5 + app/src/main/res/drawable/app_ic_rows.xml | 44 +- app/src/main/res/layout/fragment_main.xml | 2 + app/src/main/res/menu/bottom_view_menu.xml | 24 +- app/src/main/res/values-uk/strings.xml | 4 +- app/src/main/res/values/strings.xml | 4 +- .../core/adapter/NavigationFragmentAdapter.kt | 4 +- .../java/org/openedx/core/config/Config.kt | 5 + .../openedx/core/config/DashboardConfig.kt | 16 + .../org/openedx/core/data/api/CourseApi.kt | 9 + .../core/data/model/CourseAssignments.kt | 30 + .../core/data/model/CourseDateBlock.kt | 41 +- .../core/data/model/CourseEnrollments.kt | 26 +- .../openedx/core/data/model/CourseStatus.kt | 30 + .../openedx/core/data/model/EnrolledCourse.kt | 20 +- .../org/openedx/core/data/model/Progress.kt | 22 + .../room/discovery/EnrolledCourseEntity.kt | 106 ++- .../core/domain/model/CourseAssignments.kt | 10 + .../core/domain/model/CourseDateBlock.kt | 5 +- .../core/domain/model/CourseEnrollments.kt | 7 + .../openedx/core/domain/model/CourseStatus.kt | 12 + .../core/domain/model/EnrolledCourse.kt | 3 + .../org/openedx/core/domain/model/Progress.kt | 14 + .../org/openedx/core/module/DownloadWorker.kt | 9 +- .../openedx/core/module/TranscriptManager.kt | 18 +- .../core/system/notifier/CourseNotifier.kt | 4 +- .../core/system/notifier/CourseOpenBlock.kt | 3 + .../core/system/notifier/CourseRefresh.kt | 5 - .../core/system/notifier/RefreshDates.kt | 3 + .../system/notifier/RefreshDiscussions.kt | 3 + .../java/org/openedx/core/ui/ComposeCommon.kt | 54 +- .../org/openedx/core/ui/ComposeExtensions.kt | 11 + .../main/java/org/openedx/core/ui/TabItem.kt | 2 +- .../java/org/openedx/core/ui/theme/Type.kt | 8 + .../java/org/openedx/core/utils/FileUtil.kt | 21 +- .../java/org/openedx/core/utils/TimeUtils.kt | 4 +- .../main/res/drawable/core_ic_settings.xml | 20 - .../res/drawable/ic_core_chapter_icon.xml | 30 + core/src/main/res/values-night/colors.xml | 4 +- core/src/main/res/values-uk/strings.xml | 4 +- core/src/main/res/values/colors.xml | 4 +- core/src/main/res/values/strings.xml | 5 +- .../course/data/storage/CourseConverter.kt | 13 + .../container/CollapsingLayout.kt | 4 +- .../container/CourseContainerFragment.kt | 44 +- .../container}/CourseContainerTab.kt | 16 +- .../container/CourseContainerViewModel.kt | 17 +- .../presentation/dates/CourseDatesScreen.kt | 40 +- .../dates/CourseDatesViewModel.kt | 11 +- .../outline/CourseOutlineScreen.kt | 87 +- .../outline/CourseOutlineViewModel.kt | 58 +- .../section/CourseSectionFragment.kt | 52 +- .../course/presentation/ui/CourseUI.kt | 4 +- .../course/presentation/ui/CourseVideosUI.kt | 72 +- .../videos/CourseVideoViewModel.kt | 2 + .../res/drawable/ic_course_chapter_icon.xml | 31 - course/src/main/res/values/strings.xml | 6 + .../container/CourseContainerViewModelTest.kt | 7 + .../dates/CourseDatesViewModelTest.kt | 14 +- .../outline/CourseOutlineViewModelTest.kt | 11 + .../videos/CourseVideoViewModelTest.kt | 10 +- .../presentation/MyCoursesScreenTest.kt | 6 +- .../java/org/openedx/DashboardNavigator.kt | 17 + .../src/main/java/org/openedx/DashboardUI.kt | 49 + .../presentation/AllEnrolledCoursesAction.kt | 14 + .../AllEnrolledCoursesFragment.kt | 27 + .../presentation/AllEnrolledCoursesUIState.kt | 10 + .../presentation/AllEnrolledCoursesView.kt | 639 +++++++++++++ .../AllEnrolledCoursesViewModel.kt | 181 ++++ .../openedx/courses/presentation/CourseTab.kt | 5 + .../presentation/DashboardGalleryFragment.kt | 24 + .../DashboardGalleryScreenAction.kt | 13 + .../presentation/DashboardGalleryUIState.kt | 9 + .../presentation/DashboardGalleryView.kt | 863 ++++++++++++++++++ .../presentation/DashboardGalleryViewModel.kt | 130 +++ .../data/repository/DashboardRepository.kt | 32 +- .../dashboard/domain/CourseStatusFilter.kt | 18 + .../domain/interactor/DashboardInteractor.kt | 17 +- ...rdFragment.kt => DashboardListFragment.kt} | 23 +- ...ViewModel.kt => DashboardListViewModel.kt} | 3 +- .../dashboard/presentation/DashboardRouter.kt | 9 + .../main/java/org/openedx/learn/LearnType.kt | 9 + .../learn/presentation/LearnFragment.kt | 274 ++++++ .../learn/presentation/LearnViewModel.kt | 18 + .../main/res/drawable/dashboard_ic_book.xml | 44 + .../src/main/res/layout/fragment_learn.xml | 24 + dashboard/src/main/res/values/strings.xml | 20 +- .../presentation/DashboardViewModelTest.kt | 20 +- default_config/dev/config.yaml | 4 +- default_config/prod/config.yaml | 3 + default_config/stage/config.yaml | 3 + .../presentation/program/ProgramFragment.kt | 36 +- .../topics/DiscussionTopicsViewModel.kt | 9 +- .../calendar/CalendarAccessDialogFragment.kt | 6 +- .../calendar/NewCalendarDialogFragment.kt | 4 +- 101 files changed, 3380 insertions(+), 499 deletions(-) delete mode 100644 app/src/main/java/org/openedx/app/InDevelopmentFragment.kt create mode 100644 app/src/main/res/color/bottom_nav_color.xml rename app/src/main/java/org/openedx/app/adapter/MainNavigationFragmentAdapter.kt => core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt (74%) create mode 100644 core/src/main/java/org/openedx/core/config/DashboardConfig.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/CourseAssignments.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/CourseStatus.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/Progress.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/CourseAssignments.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/CourseEnrollments.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/CourseStatus.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/Progress.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/CourseOpenBlock.kt delete mode 100644 core/src/main/java/org/openedx/core/system/notifier/CourseRefresh.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/RefreshDates.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/RefreshDiscussions.kt delete mode 100644 core/src/main/res/drawable/core_ic_settings.xml create mode 100644 core/src/main/res/drawable/ic_core_chapter_icon.xml rename {core/src/main/java/org/openedx/core/presentation/course => course/src/main/java/org/openedx/course/presentation/container}/CourseContainerTab.kt (52%) delete mode 100644 course/src/main/res/drawable/ic_course_chapter_icon.xml create mode 100644 dashboard/src/main/java/org/openedx/DashboardNavigator.kt create mode 100644 dashboard/src/main/java/org/openedx/DashboardUI.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesAction.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesFragment.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesUIState.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesViewModel.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/CourseTab.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryFragment.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryScreenAction.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryUIState.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt create mode 100644 dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt create mode 100644 dashboard/src/main/java/org/openedx/dashboard/domain/CourseStatusFilter.kt rename dashboard/src/main/java/org/openedx/dashboard/presentation/{DashboardFragment.kt => DashboardListFragment.kt} (97%) rename dashboard/src/main/java/org/openedx/dashboard/presentation/{DashboardViewModel.kt => DashboardListViewModel.kt} (99%) create mode 100644 dashboard/src/main/java/org/openedx/learn/LearnType.kt create mode 100644 dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt create mode 100644 dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt create mode 100644 dashboard/src/main/res/drawable/dashboard_ic_book.xml create mode 100644 dashboard/src/main/res/layout/fragment_learn.xml diff --git a/app/src/main/java/org/openedx/app/AppRouter.kt b/app/src/main/java/org/openedx/app/AppRouter.kt index a68b550a2..17b47d11d 100644 --- a/app/src/main/java/org/openedx/app/AppRouter.kt +++ b/app/src/main/java/org/openedx/app/AppRouter.kt @@ -25,6 +25,7 @@ import org.openedx.course.presentation.unit.container.CourseUnitContainerFragmen import org.openedx.course.presentation.unit.video.VideoFullScreenFragment import org.openedx.course.presentation.unit.video.YoutubeVideoFullScreenFragment import org.openedx.course.settings.download.DownloadQueueFragment +import org.openedx.courses.presentation.AllEnrolledCoursesFragment import org.openedx.dashboard.presentation.DashboardRouter import org.openedx.discovery.presentation.DiscoveryRouter import org.openedx.discovery.presentation.NativeDiscoveryFragment @@ -123,6 +124,14 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di replaceFragmentWithBackStack(fm, UpgradeRequiredFragment()) } + override fun navigateToAllEnrolledCourses(fm: FragmentManager) { + replaceFragmentWithBackStack(fm, AllEnrolledCoursesFragment()) + } + + override fun getProgramFragmentInstance(): Fragment { + return ProgramFragment(myPrograms = true, isNestedFragment = true) + } + override fun navigateToCourseInfo( fm: FragmentManager, courseId: String, @@ -130,6 +139,18 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di ) { replaceFragmentWithBackStack(fm, CourseInfoFragment.newInstance(courseId, infoType)) } + + override fun navigateToCourseOutline( + fm: FragmentManager, + courseId: String, + courseTitle: String, + enrollmentMode: String + ) { + replaceFragmentWithBackStack( + fm, + CourseContainerFragment.newInstance(courseId, courseTitle, enrollmentMode) + ) + } //endregion //region DashboardRouter @@ -139,10 +160,12 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseId: String, courseTitle: String, enrollmentMode: String, + openTab: String, + resumeBlockId: String ) { replaceFragmentWithBackStack( fm, - CourseContainerFragment.newInstance(courseId, courseTitle, enrollmentMode) + CourseContainerFragment.newInstance(courseId, courseTitle, enrollmentMode, openTab, resumeBlockId) ) } diff --git a/app/src/main/java/org/openedx/app/InDevelopmentFragment.kt b/app/src/main/java/org/openedx/app/InDevelopmentFragment.kt deleted file mode 100644 index d8ca717d4..000000000 --- a/app/src/main/java/org/openedx/app/InDevelopmentFragment.kt +++ /dev/null @@ -1,56 +0,0 @@ -package org.openedx.app - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.Text -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId -import androidx.fragment.app.Fragment -import org.openedx.core.ui.theme.appColors -import org.openedx.core.ui.theme.appTypography - -class InDevelopmentFragment : Fragment() { - - @OptIn(ExperimentalComposeUiApi::class) - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ) = ComposeView(requireContext()).apply { - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - Scaffold( - modifier = Modifier.semantics { - testTagsAsResourceId = true - }, - ) { - Box( - modifier = Modifier - .fillMaxSize() - .padding(it) - .background(MaterialTheme.appColors.secondary), - contentAlignment = Alignment.Center - ) { - Text( - modifier = Modifier.testTag("txt_in_development"), - text = "Will be available soon", - style = MaterialTheme.appTypography.headlineMedium - ) - } - } - } - } -} diff --git a/app/src/main/java/org/openedx/app/MainFragment.kt b/app/src/main/java/org/openedx/app/MainFragment.kt index a798c4a3f..fc4fb1b22 100644 --- a/app/src/main/java/org/openedx/app/MainFragment.kt +++ b/app/src/main/java/org/openedx/app/MainFragment.kt @@ -11,15 +11,13 @@ import androidx.viewpager2.widget.ViewPager2 import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel -import org.openedx.app.adapter.MainNavigationFragmentAdapter +import org.openedx.DashboardNavigator import org.openedx.app.databinding.FragmentMainBinding -import org.openedx.core.config.Config +import org.openedx.core.adapter.NavigationFragmentAdapter import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment import org.openedx.core.presentation.global.viewBinding -import org.openedx.dashboard.presentation.DashboardFragment import org.openedx.discovery.presentation.DiscoveryNavigator import org.openedx.discovery.presentation.DiscoveryRouter -import org.openedx.discovery.presentation.program.ProgramFragment import org.openedx.profile.presentation.profile.ProfileFragment class MainFragment : Fragment(R.layout.fragment_main) { @@ -27,9 +25,8 @@ class MainFragment : Fragment(R.layout.fragment_main) { private val binding by viewBinding(FragmentMainBinding::bind) private val viewModel by viewModel() private val router by inject() - private val config by inject() - private lateinit var adapter: MainNavigationFragmentAdapter + private lateinit var adapter: NavigationFragmentAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -47,24 +44,19 @@ class MainFragment : Fragment(R.layout.fragment_main) { binding.bottomNavView.setOnItemSelectedListener { when (it.itemId) { - R.id.fragmentHome -> { - viewModel.logDiscoveryTabClickedEvent() + R.id.fragmentLearn -> { + viewModel.logMyCoursesTabClickedEvent() binding.viewPager.setCurrentItem(0, false) } - R.id.fragmentDashboard -> { - viewModel.logMyCoursesTabClickedEvent() + R.id.fragmentDiscover -> { + viewModel.logDiscoveryTabClickedEvent() binding.viewPager.setCurrentItem(1, false) } - R.id.fragmentPrograms -> { - viewModel.logMyProgramsTabClickedEvent() - binding.viewPager.setCurrentItem(2, false) - } - R.id.fragmentProfile -> { viewModel.logProfileTabClickedEvent() - binding.viewPager.setCurrentItem(3, false) + binding.viewPager.setCurrentItem(2, false) } } true @@ -79,7 +71,7 @@ class MainFragment : Fragment(R.layout.fragment_main) { viewLifecycleOwner.lifecycleScope.launch { viewModel.navigateToDiscovery.collect { shouldNavigateToDiscovery -> if (shouldNavigateToDiscovery) { - binding.bottomNavView.selectedItemId = R.id.fragmentHome + binding.bottomNavView.selectedItemId = R.id.fragmentDiscover } } } @@ -88,7 +80,7 @@ class MainFragment : Fragment(R.layout.fragment_main) { getString(ARG_COURSE_ID).takeIf { it.isNullOrBlank().not() }?.let { courseId -> val infoType = getString(ARG_INFO_TYPE) - if (config.getDiscoveryConfig().isViewTypeWebView() && infoType != null) { + if (viewModel.isDiscoveryTypeWebView && infoType != null) { router.navigateToCourseInfo(parentFragmentManager, courseId, infoType) } else { router.navigateToCourseDetail(parentFragmentManager, courseId) @@ -105,18 +97,12 @@ class MainFragment : Fragment(R.layout.fragment_main) { binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL binding.viewPager.offscreenPageLimit = 4 - val discoveryFragment = DiscoveryNavigator(viewModel.isDiscoveryTypeWebView) - .getDiscoveryFragment() - val programFragment = if (viewModel.isProgramTypeWebView) { - ProgramFragment(true) - } else { - InDevelopmentFragment() - } + val discoveryFragment = DiscoveryNavigator(viewModel.isDiscoveryTypeWebView).getDiscoveryFragment() + val dashboardFragment = DashboardNavigator(viewModel.dashboardType).getDashboardFragment() - adapter = MainNavigationFragmentAdapter(this).apply { + adapter = NavigationFragmentAdapter(this).apply { + addFragment(dashboardFragment) addFragment(discoveryFragment) - addFragment(DashboardFragment()) - addFragment(programFragment) addFragment(ProfileFragment()) } binding.viewPager.adapter = adapter diff --git a/app/src/main/java/org/openedx/app/MainViewModel.kt b/app/src/main/java/org/openedx/app/MainViewModel.kt index 6a30533ea..eed901039 100644 --- a/app/src/main/java/org/openedx/app/MainViewModel.kt +++ b/app/src/main/java/org/openedx/app/MainViewModel.kt @@ -30,16 +30,18 @@ class MainViewModel( get() = _navigateToDiscovery.asSharedFlow() val isDiscoveryTypeWebView get() = config.getDiscoveryConfig().isViewTypeWebView() - - val isProgramTypeWebView get() = config.getProgramConfig().isViewTypeWebView() + val dashboardType get() = config.getDashboardConfig().getType() override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) - notifier.notifier.onEach { - if (it is NavigationToDiscovery) { - _navigateToDiscovery.emit(true) + notifier.notifier + .onEach { + if (it is NavigationToDiscovery) { + _navigateToDiscovery.emit(true) + } } - }.distinctUntilChanged().launchIn(viewModelScope) + .distinctUntilChanged() + .launchIn(viewModelScope) } fun enableBottomBar(enable: Boolean) { @@ -54,10 +56,6 @@ class MainViewModel( logEvent(AppAnalyticsEvent.MY_COURSES) } - fun logMyProgramsTabClickedEvent() { - logEvent(AppAnalyticsEvent.MY_PROGRAMS) - } - fun logProfileTabClickedEvent() { logEvent(AppAnalyticsEvent.PROFILE) } diff --git a/app/src/main/java/org/openedx/app/di/AppModule.kt b/app/src/main/java/org/openedx/app/di/AppModule.kt index 529f00ac0..a5ec76b37 100644 --- a/app/src/main/java/org/openedx/app/di/AppModule.kt +++ b/app/src/main/java/org/openedx/app/di/AppModule.kt @@ -48,6 +48,7 @@ import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.core.system.notifier.DownloadNotifier import org.openedx.core.system.notifier.VideoNotifier +import org.openedx.core.utils.FileUtil import org.openedx.course.data.storage.CoursePreferences import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseRouter @@ -181,4 +182,6 @@ val appModule = module { factory { GoogleAuthHelper(get()) } factory { MicrosoftAuthHelper() } factory { OAuthHelper(get(), get(), get()) } + + factory { FileUtil(get()) } } diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 3c99dbc0f..cd3615e26 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -29,9 +29,11 @@ import org.openedx.course.presentation.unit.video.VideoUnitViewModel import org.openedx.course.presentation.unit.video.VideoViewModel import org.openedx.course.presentation.videos.CourseVideoViewModel import org.openedx.course.settings.download.DownloadQueueViewModel +import org.openedx.courses.presentation.AllEnrolledCoursesViewModel +import org.openedx.courses.presentation.DashboardGalleryViewModel import org.openedx.dashboard.data.repository.DashboardRepository import org.openedx.dashboard.domain.interactor.DashboardInteractor -import org.openedx.dashboard.presentation.DashboardViewModel +import org.openedx.dashboard.presentation.DashboardListViewModel import org.openedx.discovery.data.repository.DiscoveryRepository import org.openedx.discovery.domain.interactor.DiscoveryInteractor import org.openedx.discovery.presentation.NativeDiscoveryViewModel @@ -49,6 +51,7 @@ import org.openedx.discussion.presentation.search.DiscussionSearchThreadViewMode import org.openedx.discussion.presentation.threads.DiscussionAddThreadViewModel import org.openedx.discussion.presentation.threads.DiscussionThreadsViewModel import org.openedx.discussion.presentation.topics.DiscussionTopicsViewModel +import org.openedx.learn.presentation.LearnViewModel import org.openedx.profile.data.repository.ProfileRepository import org.openedx.profile.domain.interactor.ProfileInteractor import org.openedx.profile.domain.model.Account @@ -115,9 +118,12 @@ val screenModule = module { } viewModel { RestorePasswordViewModel(get(), get(), get(), get()) } - factory { DashboardRepository(get(), get(), get()) } + factory { DashboardRepository(get(), get(), get(), get()) } factory { DashboardInteractor(get()) } - viewModel { DashboardViewModel(get(), get(), get(), get(), get(), get(), get()) } + viewModel { DashboardListViewModel(get(), get(), get(), get(), get(), get(), get()) } + viewModel { DashboardGalleryViewModel(get(), get(), get(), get(), get(), get(), get()) } + viewModel { AllEnrolledCoursesViewModel(get(), get(), get(), get(), get(), get(), get()) } + viewModel { LearnViewModel(get(), get()) } factory { DiscoveryRepository(get(), get(), get()) } factory { DiscoveryInteractor(get()) } @@ -194,10 +200,11 @@ val screenModule = module { get() ) } - viewModel { (courseId: String, courseTitle: String, enrollmentMode: String) -> + viewModel { (courseId: String, courseTitle: String, enrollmentMode: String, resumeBlockId: String) -> CourseContainerViewModel( courseId, courseTitle, + resumeBlockId, enrollmentMode, get(), get(), @@ -226,6 +233,7 @@ val screenModule = module { get(), get(), get(), + get() ) } viewModel { (courseId: String) -> @@ -267,6 +275,7 @@ val screenModule = module { get(), get(), get(), + get() ) } viewModel { (courseId: String) -> BaseVideoViewModel(courseId, get()) } @@ -306,6 +315,7 @@ val screenModule = module { get(), get(), get(), + get() ) } viewModel { (courseId: String, handoutsType: String) -> diff --git a/app/src/main/res/color/bottom_nav_color.xml b/app/src/main/res/color/bottom_nav_color.xml new file mode 100644 index 000000000..4e2851e90 --- /dev/null +++ b/app/src/main/res/color/bottom_nav_color.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/app_ic_rows.xml b/app/src/main/res/drawable/app_ic_rows.xml index 41b74e9b4..eabe550d3 100644 --- a/app/src/main/res/drawable/app_ic_rows.xml +++ b/app/src/main/res/drawable/app_ic_rows.xml @@ -1,38 +1,10 @@ - - - - - - - + android:width="20dp" + android:height="17dp" + android:viewportWidth="20" + android:viewportHeight="17"> + diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index 89cf2914a..9794b7bd7 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -19,6 +19,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/background" + app:itemIconTint="@color/bottom_nav_color" + app:itemTextColor="@color/bottom_nav_color" app:labelVisibilityMode="labeled" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/menu/bottom_view_menu.xml b/app/src/main/res/menu/bottom_view_menu.xml index 60ba4f78c..f97e849f7 100644 --- a/app/src/main/res/menu/bottom_view_menu.xml +++ b/app/src/main/res/menu/bottom_view_menu.xml @@ -2,27 +2,21 @@ + android:icon="@drawable/app_ic_rows" + android:title="@string/app_navigation_learn" /> - - + android:icon="@drawable/app_ic_home" + android:title="@string/app_navigation_discovery" /> + android:icon="@drawable/app_ic_profile" + android:title="@string/app_navigation_profile" /> - \ No newline at end of file + diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 8e4178d90..17d58ded3 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -5,7 +5,7 @@ Назад Всі курси - Мої курси + Мої курси Програми Профіль - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f24815f30..baa1c2a89 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,7 +4,7 @@ Previous Discover - Dashboard + Learn Programs Profile - \ No newline at end of file + diff --git a/app/src/main/java/org/openedx/app/adapter/MainNavigationFragmentAdapter.kt b/core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt similarity index 74% rename from app/src/main/java/org/openedx/app/adapter/MainNavigationFragmentAdapter.kt rename to core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt index ccbe6f715..273c53427 100644 --- a/app/src/main/java/org/openedx/app/adapter/MainNavigationFragmentAdapter.kt +++ b/core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt @@ -1,9 +1,9 @@ -package org.openedx.app.adapter +package org.openedx.core.adapter import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter -class MainNavigationFragmentAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { +class NavigationFragmentAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { private val fragments = ArrayList() diff --git a/core/src/main/java/org/openedx/core/config/Config.kt b/core/src/main/java/org/openedx/core/config/Config.kt index b0c3f211d..4e39a0861 100644 --- a/core/src/main/java/org/openedx/core/config/Config.kt +++ b/core/src/main/java/org/openedx/core/config/Config.kt @@ -95,6 +95,10 @@ class Config(context: Context) { return getObjectOrNewInstance(PROGRAM, ProgramConfig::class.java) } + fun getDashboardConfig(): DashboardConfig { + return getObjectOrNewInstance(DASHBOARD, DashboardConfig::class.java) + } + fun getBranchConfig(): BranchConfig { return getObjectOrNewInstance(BRANCH, BranchConfig::class.java) } @@ -169,6 +173,7 @@ class Config(context: Context) { private const val PRE_LOGIN_EXPERIENCE_ENABLED = "PRE_LOGIN_EXPERIENCE_ENABLED" private const val DISCOVERY = "DISCOVERY" private const val PROGRAM = "PROGRAM" + private const val DASHBOARD = "DASHBOARD" private const val BRANCH = "BRANCH" private const val COURSE_NESTED_LIST_ENABLED = "COURSE_NESTED_LIST_ENABLED" private const val COURSE_UNIT_PROGRESS_ENABLED = "COURSE_UNIT_PROGRESS_ENABLED" diff --git a/core/src/main/java/org/openedx/core/config/DashboardConfig.kt b/core/src/main/java/org/openedx/core/config/DashboardConfig.kt new file mode 100644 index 000000000..9aa081aff --- /dev/null +++ b/core/src/main/java/org/openedx/core/config/DashboardConfig.kt @@ -0,0 +1,16 @@ +package org.openedx.core.config + +import com.google.gson.annotations.SerializedName + +data class DashboardConfig( + @SerializedName("TYPE") + private val viewType: String = DashboardType.GALLERY.name, +) { + fun getType(): DashboardType { + return DashboardType.valueOf(viewType.uppercase()) + } + + enum class DashboardType { + LIST, GALLERY + } +} 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 4a19c383d..6d30a9044 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 @@ -67,4 +67,13 @@ interface CourseApi { @GET("/api/mobile/v1/course_info/{course_id}/updates") suspend fun getAnnouncements(@Path("course_id") courseId: String): List + + @GET("/api/mobile/v4/users/{username}/course_enrollments/") + suspend fun getUserCourses( + @Path("username") username: String, + @Query("page") page: Int = 1, + @Query("page_size") pageSize: Int = 20, + @Query("status") status: String? = null, + @Query("requested_fields") fields: List = emptyList() + ): CourseEnrollments } diff --git a/core/src/main/java/org/openedx/core/data/model/CourseAssignments.kt b/core/src/main/java/org/openedx/core/data/model/CourseAssignments.kt new file mode 100644 index 000000000..ed8de3a4e --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/CourseAssignments.kt @@ -0,0 +1,30 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.data.model.room.discovery.CourseAssignmentsDb +import org.openedx.core.domain.model.CourseAssignments + +data class CourseAssignments( + @SerializedName("future_assignments") + val futureAssignments: List?, + @SerializedName("past_assignments") + val pastAssignments: List?, +) { + fun mapToDomain() = CourseAssignments( + futureAssignments = futureAssignments?.mapNotNull { + it.mapToDomain() + }, + pastAssignments = pastAssignments?.mapNotNull { + it.mapToDomain() + } + ) + + fun mapToRoomEntity() = CourseAssignmentsDb( + futureAssignments = futureAssignments?.mapNotNull { + it.mapToRoomEntity() + }, + pastAssignments = pastAssignments?.mapNotNull { + it.mapToRoomEntity() + } + ) +} diff --git a/core/src/main/java/org/openedx/core/data/model/CourseDateBlock.kt b/core/src/main/java/org/openedx/core/data/model/CourseDateBlock.kt index 887112845..d29e7a7ea 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseDateBlock.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseDateBlock.kt @@ -1,8 +1,13 @@ package org.openedx.core.data.model +import android.os.Parcelable import com.google.gson.annotations.SerializedName -import java.util.* +import kotlinx.parcelize.Parcelize +import org.openedx.core.data.model.room.discovery.CourseDateBlockDb +import org.openedx.core.domain.model.CourseDateBlock +import org.openedx.core.utils.TimeUtils +@Parcelize data class CourseDateBlock( @SerializedName("complete") val complete: Boolean = false, @@ -25,4 +30,36 @@ data class CourseDateBlock( // component blockId in-case of navigating inside the app for component available in mobile @SerializedName("first_component_block_id") val blockId: String = "", -) +) : Parcelable { + fun mapToDomain(): CourseDateBlock? { + TimeUtils.iso8601ToDate(date)?.let { + return CourseDateBlock( + complete = complete, + date = it, + assignmentType = assignmentType, + dateType = dateType, + description = description, + learnerHasAccess = learnerHasAccess, + link = link, + title = title, + blockId = blockId + ) + } ?: return null + } + + fun mapToRoomEntity(): CourseDateBlockDb? { + TimeUtils.iso8601ToDate(date)?.let { + return CourseDateBlockDb( + complete = complete, + date = it, + assignmentType = assignmentType, + dateType = dateType, + description = description, + learnerHasAccess = learnerHasAccess, + link = link, + title = title, + blockId = blockId + ) + } ?: return null + } +} diff --git a/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt b/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt index 89ecdcab4..ca28740fe 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt @@ -7,6 +7,7 @@ import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.annotations.SerializedName import java.lang.reflect.Type +import org.openedx.core.domain.model.CourseEnrollments as DomainCourseEnrollments data class CourseEnrollments( @SerializedName("enrollments") @@ -14,17 +15,38 @@ data class CourseEnrollments( @SerializedName("config") val configs: AppConfig, + + @SerializedName("primary") + val primary: EnrolledCourse?, ) { + fun mapToDomain() = DomainCourseEnrollments( + enrollments = enrollments.mapToDomain(), + configs = configs.mapToDomain(), + primary = primary?.mapToDomain() + ) + class Deserializer : JsonDeserializer { override fun deserialize( json: JsonElement?, typeOfT: Type?, - context: JsonDeserializationContext? + context: JsonDeserializationContext?, ): CourseEnrollments { val enrollments = deserializeEnrollments(json) val appConfig = deserializeAppConfig(json) + val primaryCourse = deserializePrimaryCourse(json) - return CourseEnrollments(enrollments, appConfig) + return CourseEnrollments(enrollments, appConfig, primaryCourse) + } + + private fun deserializePrimaryCourse(json: JsonElement?): EnrolledCourse? { + return try { + Gson().fromJson( + (json as JsonObject).get("primary"), + EnrolledCourse::class.java + ) + } catch (ex: Exception) { + null + } } private fun deserializeEnrollments(json: JsonElement?): DashboardCourseList { diff --git a/core/src/main/java/org/openedx/core/data/model/CourseStatus.kt b/core/src/main/java/org/openedx/core/data/model/CourseStatus.kt new file mode 100644 index 000000000..53cb028b4 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/CourseStatus.kt @@ -0,0 +1,30 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.data.model.room.discovery.CourseStatusDb +import org.openedx.core.domain.model.CourseStatus + +data class CourseStatus( + @SerializedName("last_visited_module_id") + val lastVisitedModuleId: String?, + @SerializedName("last_visited_module_path") + val lastVisitedModulePath: List?, + @SerializedName("last_visited_block_id") + val lastVisitedBlockId: String?, + @SerializedName("last_visited_unit_display_name") + val lastVisitedUnitDisplayName: String?, +) { + fun mapToDomain() = CourseStatus( + lastVisitedModuleId = lastVisitedModuleId ?: "", + lastVisitedModulePath = lastVisitedModulePath ?: emptyList(), + lastVisitedBlockId = lastVisitedBlockId ?: "", + lastVisitedUnitDisplayName = lastVisitedUnitDisplayName ?: "" + ) + + fun mapToRoomEntity() = CourseStatusDb( + lastVisitedModuleId = lastVisitedModuleId ?: "", + lastVisitedModulePath = lastVisitedModulePath ?: emptyList(), + lastVisitedBlockId = lastVisitedBlockId ?: "", + lastVisitedUnitDisplayName = lastVisitedUnitDisplayName ?: "" + ) +} diff --git a/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt b/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt index 984794698..edf8bbce3 100644 --- a/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt +++ b/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt @@ -2,8 +2,10 @@ package org.openedx.core.data.model import com.google.gson.annotations.SerializedName import org.openedx.core.data.model.room.discovery.EnrolledCourseEntity +import org.openedx.core.data.model.room.discovery.ProgressDb import org.openedx.core.domain.model.EnrolledCourse import org.openedx.core.utils.TimeUtils +import org.openedx.core.domain.model.Progress as ProgressDomain data class EnrolledCourse( @SerializedName("audit_access_expires") @@ -17,7 +19,13 @@ data class EnrolledCourse( @SerializedName("course") val course: EnrolledCourseData?, @SerializedName("certificate") - val certificate: Certificate? + val certificate: Certificate?, + @SerializedName("course_progress") + val progress: Progress?, + @SerializedName("course_status") + val courseStatus: CourseStatus?, + @SerializedName("course_assignments") + val courseAssignments: CourseAssignments? ) { fun mapToDomain(): EnrolledCourse { return EnrolledCourse( @@ -26,7 +34,10 @@ data class EnrolledCourse( mode = mode ?: "", isActive = isActive ?: false, course = course?.mapToDomain()!!, - certificate = certificate?.mapToDomain() + certificate = certificate?.mapToDomain(), + progress = progress?.mapToDomain() ?: ProgressDomain.DEFAULT_PROGRESS, + courseStatus = courseStatus?.mapToDomain(), + courseAssignments = courseAssignments?.mapToDomain() ) } @@ -38,7 +49,10 @@ data class EnrolledCourse( mode = mode ?: "", isActive = isActive ?: false, course = course?.mapToRoomEntity()!!, - certificate = certificate?.mapToRoomEntity() + certificate = certificate?.mapToRoomEntity(), + progress = progress?.mapToRoomEntity() ?: ProgressDb.DEFAULT_PROGRESS, + courseStatus = courseStatus?.mapToRoomEntity(), + courseAssignments = courseAssignments?.mapToRoomEntity() ) } } diff --git a/core/src/main/java/org/openedx/core/data/model/Progress.kt b/core/src/main/java/org/openedx/core/data/model/Progress.kt new file mode 100644 index 000000000..d4813c14c --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/Progress.kt @@ -0,0 +1,22 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.data.model.room.discovery.ProgressDb +import org.openedx.core.domain.model.Progress + +data class Progress( + @SerializedName("assignments_completed") + val assignmentsCompleted: Int?, + @SerializedName("total_assignments_count") + val totalAssignmentsCount: Int?, +) { + fun mapToDomain() = Progress( + assignmentsCompleted = assignmentsCompleted ?: 0, + totalAssignmentsCount = totalAssignmentsCount ?: 0 + ) + + fun mapToRoomEntity() = ProgressDb( + assignmentsCompleted = assignmentsCompleted ?: 0, + totalAssignmentsCount = totalAssignmentsCount ?: 0 + ) +} diff --git a/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt b/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt index 05aab3bdd..e019f6300 100644 --- a/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt +++ b/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt @@ -4,9 +4,19 @@ import androidx.room.ColumnInfo import androidx.room.Embedded import androidx.room.Entity import androidx.room.PrimaryKey +import org.openedx.core.data.model.DateType import org.openedx.core.data.model.room.MediaDb -import org.openedx.core.domain.model.* +import org.openedx.core.domain.model.Certificate +import org.openedx.core.domain.model.CourseAssignments +import org.openedx.core.domain.model.CourseDateBlock +import org.openedx.core.domain.model.CourseSharingUtmParameters +import org.openedx.core.domain.model.CourseStatus +import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.domain.model.EnrolledCourseData +import org.openedx.core.domain.model.Progress import org.openedx.core.utils.TimeUtils +import java.util.Date @Entity(tableName = "course_enrolled_table") data class EnrolledCourseEntity( @@ -25,6 +35,12 @@ data class EnrolledCourseEntity( val course: EnrolledCourseDataDb, @Embedded val certificate: CertificateDb?, + @Embedded + val progress: ProgressDb, + @Embedded + val courseStatus: CourseStatusDb?, + @Embedded + val courseAssignments: CourseAssignmentsDb?, ) { fun mapToDomain(): EnrolledCourse { @@ -34,7 +50,10 @@ data class EnrolledCourseEntity( mode, isActive, course.mapToDomain(), - certificate?.mapToDomain() + certificate?.mapToDomain(), + progress.mapToDomain(), + courseStatus?.mapToDomain(), + courseAssignments?.mapToDomain() ) } } @@ -79,7 +98,7 @@ data class EnrolledCourseDataDb( @ColumnInfo("videoOutline") val videoOutline: String, @ColumnInfo("isSelfPaced") - val isSelfPaced: Boolean + val isSelfPaced: Boolean, ) { fun mapToDomain(): EnrolledCourseData { return EnrolledCourseData( @@ -119,7 +138,7 @@ data class CoursewareAccessDb( @ColumnInfo("additionalContextUserMessage") val additionalContextUserMessage: String, @ColumnInfo("userFragment") - val userFragment: String + val userFragment: String, ) { fun mapToDomain(): CoursewareAccess { @@ -137,7 +156,7 @@ data class CoursewareAccessDb( data class CertificateDb( @ColumnInfo("certificateURL") - val certificateURL: String? + val certificateURL: String?, ) { fun mapToDomain() = Certificate(certificateURL) } @@ -146,9 +165,82 @@ data class CourseSharingUtmParametersDb( @ColumnInfo("facebook") val facebook: String, @ColumnInfo("twitter") - val twitter: String + val twitter: String, ) { fun mapToDomain() = CourseSharingUtmParameters( facebook, twitter ) -} \ No newline at end of file +} + +data class ProgressDb( + @ColumnInfo("assignments_completed") + val assignmentsCompleted: Int, + @ColumnInfo("total_assignments_count") + val totalAssignmentsCount: Int, +) { + companion object { + val DEFAULT_PROGRESS = ProgressDb(0, 0) + } + + fun mapToDomain() = Progress(assignmentsCompleted, totalAssignmentsCount) +} + +data class CourseStatusDb( + @ColumnInfo("lastVisitedModuleId") + val lastVisitedModuleId: String, + @ColumnInfo("lastVisitedModulePath") + val lastVisitedModulePath: List, + @ColumnInfo("lastVisitedBlockId") + val lastVisitedBlockId: String, + @ColumnInfo("lastVisitedUnitDisplayName") + val lastVisitedUnitDisplayName: String, +) { + fun mapToDomain() = CourseStatus( + lastVisitedModuleId, lastVisitedModulePath, lastVisitedBlockId, lastVisitedUnitDisplayName + ) +} + +data class CourseAssignmentsDb( + @ColumnInfo("futureAssignments") + val futureAssignments: List?, + @ColumnInfo("pastAssignments") + val pastAssignments: List?, +) { + fun mapToDomain() = CourseAssignments( + futureAssignments = futureAssignments?.map { it.mapToDomain() }, + pastAssignments = pastAssignments?.map { it.mapToDomain() } + ) +} + +data class CourseDateBlockDb( + @ColumnInfo("title") + val title: String = "", + @ColumnInfo("description") + val description: String = "", + @ColumnInfo("link") + val link: String = "", + @ColumnInfo("blockId") + val blockId: String = "", + @ColumnInfo("learnerHasAccess") + val learnerHasAccess: Boolean = false, + @ColumnInfo("complete") + val complete: Boolean = false, + @Embedded + val date: Date, + @ColumnInfo("dateType") + val dateType: DateType = DateType.NONE, + @ColumnInfo("assignmentType") + val assignmentType: String? = "", +) { + fun mapToDomain() = CourseDateBlock( + title = title, + description = description, + link = link, + blockId = blockId, + learnerHasAccess = learnerHasAccess, + complete = complete, + date = date, + dateType = dateType, + assignmentType = assignmentType + ) +} diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseAssignments.kt b/core/src/main/java/org/openedx/core/domain/model/CourseAssignments.kt new file mode 100644 index 000000000..feb039fc7 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/CourseAssignments.kt @@ -0,0 +1,10 @@ +package org.openedx.core.domain.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class CourseAssignments( + val futureAssignments: List?, + val pastAssignments: List? +): Parcelable diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseDateBlock.kt b/core/src/main/java/org/openedx/core/domain/model/CourseDateBlock.kt index 7e91c59fa..394ebdd56 100644 --- a/core/src/main/java/org/openedx/core/domain/model/CourseDateBlock.kt +++ b/core/src/main/java/org/openedx/core/domain/model/CourseDateBlock.kt @@ -1,10 +1,13 @@ package org.openedx.core.domain.model +import android.os.Parcelable +import kotlinx.parcelize.Parcelize import org.openedx.core.data.model.DateType import org.openedx.core.utils.isTimeLessThan24Hours import org.openedx.core.utils.isToday import java.util.Date +@Parcelize data class CourseDateBlock( val title: String = "", val description: String = "", @@ -15,7 +18,7 @@ data class CourseDateBlock( val date: Date, val dateType: DateType = DateType.NONE, val assignmentType: String? = "", -) { +) : Parcelable { fun isCompleted(): Boolean { return complete || (dateType in setOf( DateType.COURSE_START_DATE, diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseEnrollments.kt b/core/src/main/java/org/openedx/core/domain/model/CourseEnrollments.kt new file mode 100644 index 000000000..6606902c2 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/CourseEnrollments.kt @@ -0,0 +1,7 @@ +package org.openedx.core.domain.model + +data class CourseEnrollments( + val enrollments: DashboardCourseList, + val configs: AppConfig, + val primary: EnrolledCourse?, +) diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseStatus.kt b/core/src/main/java/org/openedx/core/domain/model/CourseStatus.kt new file mode 100644 index 000000000..aef245f67 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/CourseStatus.kt @@ -0,0 +1,12 @@ +package org.openedx.core.domain.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class CourseStatus( + val lastVisitedModuleId: String, + val lastVisitedModulePath: List, + val lastVisitedBlockId: String, + val lastVisitedUnitDisplayName: String, +) : Parcelable diff --git a/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt b/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt index 8e339b3f6..184fc3aa4 100644 --- a/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt +++ b/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt @@ -12,4 +12,7 @@ data class EnrolledCourse( val isActive: Boolean, val course: EnrolledCourseData, val certificate: Certificate?, + val progress: Progress, + val courseStatus: CourseStatus?, + val courseAssignments: CourseAssignments? ) : Parcelable diff --git a/core/src/main/java/org/openedx/core/domain/model/Progress.kt b/core/src/main/java/org/openedx/core/domain/model/Progress.kt new file mode 100644 index 000000000..5d8ea19f8 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/Progress.kt @@ -0,0 +1,14 @@ +package org.openedx.core.domain.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Progress( + val assignmentsCompleted: Int, + val totalAssignmentsCount: Int, +) : Parcelable { + companion object { + val DEFAULT_PROGRESS = Progress(0, 0) + } +} diff --git a/core/src/main/java/org/openedx/core/module/DownloadWorker.kt b/core/src/main/java/org/openedx/core/module/DownloadWorker.kt index 9234ec023..736a1b1ce 100644 --- a/core/src/main/java/org/openedx/core/module/DownloadWorker.kt +++ b/core/src/main/java/org/openedx/core/module/DownloadWorker.kt @@ -23,11 +23,12 @@ import org.openedx.core.module.download.CurrentProgress import org.openedx.core.module.download.FileDownloader import org.openedx.core.system.notifier.DownloadNotifier import org.openedx.core.system.notifier.DownloadProgressChanged +import org.openedx.core.utils.FileUtil import java.io.File class DownloadWorker( val context: Context, - parameters: WorkerParameters + parameters: WorkerParameters, ) : CoroutineWorker(context, parameters), CoroutineScope { private val notificationManager = @@ -41,11 +42,7 @@ class DownloadWorker( private var downloadEnqueue = listOf() - private val folder = File( - context.externalCacheDir.toString() + File.separator + - context.getString(R.string.app_name) - .replace(Regex("\\s"), "_") - ) + private val folder = FileUtil(context).getExternalAppDir() private var currentDownload: DownloadModel? = null private var lastUpdateTime = 0L diff --git a/core/src/main/java/org/openedx/core/module/TranscriptManager.kt b/core/src/main/java/org/openedx/core/module/TranscriptManager.kt index 863586900..c08870a33 100644 --- a/core/src/main/java/org/openedx/core/module/TranscriptManager.kt +++ b/core/src/main/java/org/openedx/core/module/TranscriptManager.kt @@ -1,9 +1,12 @@ package org.openedx.core.module import android.content.Context -import org.openedx.core.module.download.AbstractDownloader -import org.openedx.core.utils.* import okhttp3.OkHttpClient +import org.openedx.core.module.download.AbstractDownloader +import org.openedx.core.utils.Directories +import org.openedx.core.utils.FileUtil +import org.openedx.core.utils.IOUtils +import org.openedx.core.utils.Sha1Util import subtitleFile.FormatSRT import subtitleFile.TimedTextObject import java.io.File @@ -14,7 +17,7 @@ import java.nio.charset.Charset import java.util.concurrent.TimeUnit class TranscriptManager( - val context: Context + val context: Context, ) { private val transcriptDownloader = object : AbstractDownloader() { @@ -28,7 +31,9 @@ class TranscriptManager( val transcriptDir = getTranscriptDir() ?: return false val hash = Sha1Util.SHA1(url) val file = File(transcriptDir, hash) - return file.exists() && System.currentTimeMillis() - file.lastModified() < TimeUnit.HOURS.toMillis(5) + return file.exists() && System.currentTimeMillis() - file.lastModified() < TimeUnit.HOURS.toMillis( + 5 + ) } fun get(url: String): String? { @@ -113,7 +118,7 @@ class TranscriptManager( } private fun getTranscriptDir(): File? { - val externalAppDir: File = FileUtil.getExternalAppDir(context) + val externalAppDir: File = FileUtil(context).getExternalAppDir() if (externalAppDir.exists()) { val videosDir = File(externalAppDir, Directories.VIDEOS.name) val transcriptDir = File(videosDir, Directories.SUBTITLES.name) @@ -122,5 +127,4 @@ class TranscriptManager( } return null } - -} \ No newline at end of file +} diff --git a/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt b/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt index f4908bdef..527a7ce51 100644 --- a/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt +++ b/core/src/main/java/org/openedx/core/system/notifier/CourseNotifier.kt @@ -18,5 +18,7 @@ class CourseNotifier { suspend fun send(event: CalendarSyncEvent) = channel.emit(event) suspend fun send(event: CourseDatesShifted) = channel.emit(event) suspend fun send(event: CourseLoading) = channel.emit(event) - suspend fun send(event: CourseRefresh) = channel.emit(event) + suspend fun send(event: CourseOpenBlock) = channel.emit(event) + suspend fun send(event: RefreshDates) = channel.emit(event) + suspend fun send(event: RefreshDiscussions) = channel.emit(event) } diff --git a/core/src/main/java/org/openedx/core/system/notifier/CourseOpenBlock.kt b/core/src/main/java/org/openedx/core/system/notifier/CourseOpenBlock.kt new file mode 100644 index 000000000..6704f1256 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/CourseOpenBlock.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier + +data class CourseOpenBlock(val blockId: String) : CourseEvent diff --git a/core/src/main/java/org/openedx/core/system/notifier/CourseRefresh.kt b/core/src/main/java/org/openedx/core/system/notifier/CourseRefresh.kt deleted file mode 100644 index c85fc595d..000000000 --- a/core/src/main/java/org/openedx/core/system/notifier/CourseRefresh.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.openedx.core.system.notifier - -import org.openedx.core.presentation.course.CourseContainerTab - -data class CourseRefresh(val courseContainerTab: CourseContainerTab) : CourseEvent diff --git a/core/src/main/java/org/openedx/core/system/notifier/RefreshDates.kt b/core/src/main/java/org/openedx/core/system/notifier/RefreshDates.kt new file mode 100644 index 000000000..779d1b924 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/RefreshDates.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier + +object RefreshDates : CourseEvent diff --git a/core/src/main/java/org/openedx/core/system/notifier/RefreshDiscussions.kt b/core/src/main/java/org/openedx/core/system/notifier/RefreshDiscussions.kt new file mode 100644 index 000000000..5c51f605b --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/RefreshDiscussions.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier + +object RefreshDiscussions : CourseEvent diff --git a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt index 1692e7a4d..6c57df741 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape @@ -48,6 +49,7 @@ import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.ManageAccounts import androidx.compose.material.icons.filled.Search import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -199,8 +201,8 @@ fun Toolbar( onClick = { onSettingsClick() } ) { Icon( - painter = painterResource(id = R.drawable.core_ic_settings), - tint = MaterialTheme.appColors.primary, + imageVector = Icons.Default.ManageAccounts, + tint = MaterialTheme.appColors.textAccent, contentDescription = stringResource(id = R.string.core_accessibility_settings) ) } @@ -939,22 +941,23 @@ fun TextIcon( icon: ImageVector, color: Color, textStyle: TextStyle = MaterialTheme.appTypography.bodySmall, - iconModifier: Modifier = Modifier, + modifier: Modifier = Modifier, + iconModifier: Modifier? = null, onClick: (() -> Unit)? = null, ) { - val modifier = if (onClick == null) { - Modifier + val rowModifier = if (onClick == null) { + modifier } else { - Modifier.noRippleClickable { onClick.invoke() } + modifier.clickable { onClick.invoke() } } Row( - modifier = modifier, + modifier = rowModifier, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp) ) { Text(text = text, color = color, style = textStyle) Icon( - modifier = iconModifier.size((textStyle.fontSize.value + 4).dp), + modifier = iconModifier ?: Modifier.size((textStyle.fontSize.value + 4).dp), imageVector = icon, contentDescription = null, tint = color @@ -1213,17 +1216,22 @@ fun RoundTabsBar( modifier: Modifier = Modifier, items: List, pagerState: PagerState, + contentPadding: PaddingValues = PaddingValues(), + withPager: Boolean = false, rowState: LazyListState = rememberLazyListState(), - onPageChange: (Int) -> Unit + onTabClicked: (Int) -> Unit = { } ) { + // The pager state does not work without the pager and the tabs do not change. + if (!withPager) { + HorizontalPager(state = pagerState) { } + } + val scope = rememberCoroutineScope() - val windowSize = rememberWindowSize() - val horizontalPadding = if (!windowSize.isTablet) 12.dp else 98.dp LazyRow( modifier = modifier, state = rowState, horizontalArrangement = Arrangement.spacedBy(8.dp), - contentPadding = PaddingValues(vertical = 16.dp, horizontal = horizontalPadding), + contentPadding = contentPadding, ) { itemsIndexed(items) { index, item -> val isSelected = pagerState.currentPage == index @@ -1246,10 +1254,11 @@ fun RoundTabsBar( .clickable { scope.launch { pagerState.scrollToPage(index) - onPageChange(index) + rowState.animateScrollToItem(index) + onTabClicked(index) } } - .padding(horizontal = 12.dp), + .padding(horizontal = 16.dp), item = item, contentColor = contentColor ) @@ -1268,12 +1277,15 @@ private fun RoundTab( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center ) { - Icon( - painter = rememberVectorPainter(item.icon), - tint = contentColor, - contentDescription = null - ) - Spacer(modifier = Modifier.width(4.dp)) + val icon = item.icon + if (icon != null) { + Icon( + painter = rememberVectorPainter(icon), + tint = contentColor, + contentDescription = null + ) + Spacer(modifier = Modifier.width(4.dp)) + } Text( text = stringResource(item.labelResId), color = contentColor @@ -1374,7 +1386,7 @@ private fun RoundTabsBarPreview() { items = listOf(mockTab, mockTab, mockTab), rowState = rememberLazyListState(), pagerState = rememberPagerState(pageCount = { 3 }), - onPageChange = { } + onTabClicked = { } ) } } diff --git a/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt b/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt index 1659a0417..5165619b6 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeExtensions.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -77,6 +78,16 @@ fun LazyListState.shouldLoadMore(rememberedIndex: MutableState, threshold: return false } +fun LazyGridState.shouldLoadMore(rememberedIndex: MutableState, threshold: Int): Boolean { + val firstVisibleIndex = this.firstVisibleItemIndex + if (rememberedIndex.value != firstVisibleIndex) { + rememberedIndex.value = firstVisibleIndex + val lastVisibleIndex = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0 + return lastVisibleIndex >= layoutInfo.totalItemsCount - 1 - threshold + } + return false +} + fun Modifier.statusBarsInset(): Modifier = composed { val topInset = (LocalContext.current as? InsetHolder)?.topInset ?: 0 return@composed this diff --git a/core/src/main/java/org/openedx/core/ui/TabItem.kt b/core/src/main/java/org/openedx/core/ui/TabItem.kt index 65a88861e..d6952c010 100644 --- a/core/src/main/java/org/openedx/core/ui/TabItem.kt +++ b/core/src/main/java/org/openedx/core/ui/TabItem.kt @@ -6,5 +6,5 @@ import androidx.compose.ui.graphics.vector.ImageVector interface TabItem { @get:StringRes val labelResId: Int - val icon: ImageVector + val icon: ImageVector? } diff --git a/core/src/main/java/org/openedx/core/ui/theme/Type.kt b/core/src/main/java/org/openedx/core/ui/theme/Type.kt index 0160196f9..52d9adebb 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Type.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Type.kt @@ -17,6 +17,7 @@ data class AppTypography( val displayLarge: TextStyle, val displayMedium: TextStyle, val displaySmall: TextStyle, + val headlineBold: TextStyle, val headlineLarge: TextStyle, val headlineMedium: TextStyle, val headlineSmall: TextStyle, @@ -72,6 +73,13 @@ internal val LocalTypography = staticCompositionLocalOf { letterSpacing = 0.sp, fontFamily = fontFamily ), + headlineBold = TextStyle( + fontSize = 34.sp, + lineHeight = 24.sp, + fontWeight = FontWeight.Bold, + letterSpacing = 0.sp, + fontFamily = fontFamily + ), headlineMedium = TextStyle( fontSize = 28.sp, lineHeight = 36.sp, diff --git a/core/src/main/java/org/openedx/core/utils/FileUtil.kt b/core/src/main/java/org/openedx/core/utils/FileUtil.kt index 001d03f4f..2f5c2b2e5 100644 --- a/core/src/main/java/org/openedx/core/utils/FileUtil.kt +++ b/core/src/main/java/org/openedx/core/utils/FileUtil.kt @@ -1,11 +1,13 @@ package org.openedx.core.utils import android.content.Context +import com.google.gson.Gson +import com.google.gson.GsonBuilder import java.io.File -object FileUtil { +class FileUtil(val context: Context) { - fun getExternalAppDir(context: Context): File { + fun getExternalAppDir(): File { val dir = context.externalCacheDir.toString() + File.separator + context.getString(org.openedx.core.R.string.app_name).replace(Regex("\\s"), "_") val file = File(dir) @@ -13,7 +15,22 @@ object FileUtil { return file } + inline fun saveObjectToFile(obj: T, fileName: String = "${T::class.java.simpleName}.json") { + val gson: Gson = GsonBuilder().setPrettyPrinting().create() + val jsonString = gson.toJson(obj) + File(getExternalAppDir().path + fileName).writeText(jsonString) + } + inline fun getObjectFromFile(fileName: String = "${T::class.java.simpleName}.json"): T? { + val file = File(getExternalAppDir().path + fileName) + return if (file.exists()) { + val gson: Gson = GsonBuilder().setPrettyPrinting().create() + val jsonString = file.readText() + gson.fromJson(jsonString, T::class.java) + } else { + null + } + } } enum class Directories { diff --git a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt index d77a1ab5e..9ccfaebef 100644 --- a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt +++ b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt @@ -59,7 +59,7 @@ object TimeUtils { private fun dateToCourseDate(resourceManager: ResourceManager, date: Date?): String { return formatDate( - format = resourceManager.getString(R.string.core_date_format_MMMM_dd), date = date + format = resourceManager.getString(R.string.core_date_format_MMM_dd_yyyy), date = date ) } @@ -152,7 +152,7 @@ object TimeUtils { ) } else { resourceManager.getString( - R.string.core_label_ending, dateToCourseDate(resourceManager, end) + R.string.core_label_ends, dateToCourseDate(resourceManager, end) ) } } diff --git a/core/src/main/res/drawable/core_ic_settings.xml b/core/src/main/res/drawable/core_ic_settings.xml deleted file mode 100644 index a86316516..000000000 --- a/core/src/main/res/drawable/core_ic_settings.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - diff --git a/core/src/main/res/drawable/ic_core_chapter_icon.xml b/core/src/main/res/drawable/ic_core_chapter_icon.xml new file mode 100644 index 000000000..9ee00fed7 --- /dev/null +++ b/core/src/main/res/drawable/ic_core_chapter_icon.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/core/src/main/res/values-night/colors.xml b/core/src/main/res/values-night/colors.xml index 5a7d9d3bd..d6f9f1a14 100644 --- a/core/src/main/res/values-night/colors.xml +++ b/core/src/main/res/values-night/colors.xml @@ -3,4 +3,6 @@ #FF19212F #5478F9 #19212F - \ No newline at end of file + #879FF5 + #8E9BAE + diff --git a/core/src/main/res/values-uk/strings.xml b/core/src/main/res/values-uk/strings.xml index f20cd28e1..2aab8871c 100644 --- a/core/src/main/res/values-uk/strings.xml +++ b/core/src/main/res/values-uk/strings.xml @@ -13,7 +13,7 @@ Виберіть значення Починається %1$s Закінчився %1$s - Закінчується %1$s + Закінчується %1$s Термін дії курсу закінчується %1$s Термін дії курсу закінчується %1$s Термін дії курсу минув %1$s @@ -31,7 +31,7 @@ Обліковий запис користувача не активовано. Будь ласка, спочатку активуйте свій обліковий запис. Надіслати електронний лист за допомогою ... Не встановлено жодного поштового клієнта - dd MMMM + dd MMMM, yyyy dd MMM yyyy HH:mm Оновлення додатку Ми рекомендуємо вам оновитись до останньої версії. Оновіться зараз, щоб отримати останні функції та виправлення. diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml index d6d7f456d..57a25d9ed 100644 --- a/core/src/main/res/values/colors.xml +++ b/core/src/main/res/values/colors.xml @@ -3,4 +3,6 @@ #FFFFFF #3C68FF #517BFE - \ No newline at end of file + #3C68FF + #97A5BB + diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 668c61935..afbc28243 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -18,7 +18,7 @@ Select value Starting %1$s Ended %1$s - Ending %1$s + Ends %1$s Course access expires %1$s Course access expires on %1$s Course access expired %1$s @@ -46,7 +46,7 @@ OS version: Device model: Feedback - MMMM dd + MMM dd, yyyy dd MMM yyyy hh:mm aaa App Update We recommend that you update to the latest version. Upgrade now to receive the latest features and fixes. @@ -166,7 +166,6 @@ - Home Videos Discussions diff --git a/course/src/main/java/org/openedx/course/data/storage/CourseConverter.kt b/course/src/main/java/org/openedx/course/data/storage/CourseConverter.kt index 91ac5a610..1865a3c34 100644 --- a/course/src/main/java/org/openedx/course/data/storage/CourseConverter.kt +++ b/course/src/main/java/org/openedx/course/data/storage/CourseConverter.kt @@ -4,6 +4,7 @@ import androidx.room.TypeConverter import com.google.gson.Gson import org.openedx.core.data.model.room.BlockDb import org.openedx.core.data.model.room.VideoInfoDb +import org.openedx.core.data.model.room.discovery.CourseDateBlockDb import org.openedx.core.extension.genericType class CourseConverter { @@ -57,4 +58,16 @@ class CourseConverter { return gson.toJson(map) } + @TypeConverter + fun fromListOfCourseDateBlockDb(value: List): String { + val json = Gson().toJson(value) + return json.toString() + } + + @TypeConverter + fun toListOfCourseDateBlockDb(value: String): List { + val type = genericType>() + return Gson().fromJson(value, type) + } + } diff --git a/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt b/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt index b5d73adaf..64ba858d8 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt @@ -64,7 +64,6 @@ import androidx.compose.ui.unit.dp import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.ui.RoundTabsBar import org.openedx.core.ui.displayCutoutForLandscape import org.openedx.core.ui.rememberWindowSize @@ -748,8 +747,7 @@ private fun CollapsingLayoutPreview() { RoundTabsBar( items = CourseContainerTab.entries, rowState = rememberLazyListState(), - pagerState = rememberPagerState(pageCount = { 5 }), - onPageChange = { } + pagerState = rememberPagerState(pageCount = { CourseContainerTab.entries.size }) ) }, onBackClick = {}, 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 2d80608ef..a55ca6bc9 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 @@ -5,6 +5,7 @@ import android.view.View import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -53,7 +54,6 @@ import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import org.openedx.core.extension.takeIfNotEmpty -import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.presentation.global.viewBinding import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialog import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType @@ -83,7 +83,8 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { parametersOf( requireArguments().getString(ARG_COURSE_ID, ""), requireArguments().getString(ARG_TITLE, ""), - requireArguments().getString(ARG_ENROLLMENT_MODE, "") + requireArguments().getString(ARG_ENROLLMENT_MODE, ""), + requireArguments().getString(ARG_RESUME_BLOCK, "") ) } @@ -255,16 +256,22 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { const val ARG_COURSE_ID = "courseId" const val ARG_TITLE = "title" const val ARG_ENROLLMENT_MODE = "enrollmentMode" + const val ARG_OPEN_TAB = "open_tab" + const val ARG_RESUME_BLOCK = "resume_block" fun newInstance( courseId: String, courseTitle: String, enrollmentMode: String, + openTab: String = CourseContainerTab.HOME.name, + resumeBlockId: String = "" ): CourseContainerFragment { val fragment = CourseContainerFragment() fragment.arguments = bundleOf( ARG_COURSE_ID to courseId, ARG_TITLE to courseTitle, - ARG_ENROLLMENT_MODE to enrollmentMode + ARG_ENROLLMENT_MODE to enrollmentMode, + ARG_OPEN_TAB to openTab, + ARG_RESUME_BLOCK to resumeBlockId ) return fragment } @@ -295,9 +302,21 @@ fun CourseDashboard( val refreshing by viewModel.refreshing.collectAsState(true) val courseImage by viewModel.courseImage.collectAsState() val uiMessage by viewModel.uiMessage.collectAsState(null) - val dataReady = viewModel.dataReady.observeAsState() + val openTab = bundle.getString(CourseContainerFragment.ARG_OPEN_TAB, CourseContainerTab.HOME.name) + val requiredTab = when (openTab.uppercase()) { + CourseContainerTab.HOME.name -> CourseContainerTab.HOME + CourseContainerTab.VIDEOS.name -> CourseContainerTab.VIDEOS + CourseContainerTab.DATES.name -> CourseContainerTab.DATES + CourseContainerTab.DISCUSSIONS.name -> CourseContainerTab.DISCUSSIONS + CourseContainerTab.MORE.name -> CourseContainerTab.MORE + else -> CourseContainerTab.HOME + } - val pagerState = rememberPagerState(pageCount = { CourseContainerTab.entries.size }) + val pagerState = rememberPagerState( + initialPage = CourseContainerTab.entries.indexOf(requiredTab), + pageCount = { CourseContainerTab.entries.size } + ) + val dataReady = viewModel.dataReady.observeAsState() val tabState = rememberLazyListState() val snackState = remember { SnackbarHostState() } val pullRefreshState = rememberPullRefreshState( @@ -342,9 +361,11 @@ fun CourseDashboard( if (isNavigationEnabled) { RoundTabsBar( items = CourseContainerTab.entries, + contentPadding = PaddingValues(horizontal = 12.dp, vertical = 16.dp), rowState = tabState, pagerState = pagerState, - onPageChange = viewModel::courseContainerTabClickedEvent + withPager = true, + onTabClicked = viewModel::courseContainerTabClickedEvent ) } else { Spacer(modifier = Modifier.height(52.dp)) @@ -430,7 +451,7 @@ fun DashboardPager( CourseContainerTab.HOME -> { CourseOutlineScreen( windowSize = windowSize, - courseOutlineViewModel = koinViewModel( + viewModel = koinViewModel( parameters = { parametersOf( bundle.getString(CourseContainerFragment.ARG_COURSE_ID, ""), @@ -438,7 +459,6 @@ fun DashboardPager( ) } ), - courseRouter = viewModel.courseRouter, fragmentManager = fragmentManager, onResetDatesClick = { viewModel.onRefresh(CourseContainerTab.DATES) @@ -449,7 +469,7 @@ fun DashboardPager( CourseContainerTab.VIDEOS -> { CourseVideosScreen( windowSize = windowSize, - courseVideoViewModel = koinViewModel( + viewModel = koinViewModel( parameters = { parametersOf( bundle.getString(CourseContainerFragment.ARG_COURSE_ID, ""), @@ -457,14 +477,13 @@ fun DashboardPager( ) } ), - fragmentManager = fragmentManager, - courseRouter = viewModel.courseRouter, + fragmentManager = fragmentManager ) } CourseContainerTab.DATES -> { CourseDatesScreen( - courseDatesViewModel = koinViewModel( + viewModel = koinViewModel( parameters = { parametersOf( bundle.getString(CourseContainerFragment.ARG_COURSE_ID, ""), @@ -474,7 +493,6 @@ fun DashboardPager( } ), windowSize = windowSize, - courseRouter = viewModel.courseRouter, fragmentManager = fragmentManager, isFragmentResumed = isResumed, updateCourseStructure = { diff --git a/core/src/main/java/org/openedx/core/presentation/course/CourseContainerTab.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerTab.kt similarity index 52% rename from core/src/main/java/org/openedx/core/presentation/course/CourseContainerTab.kt rename to course/src/main/java/org/openedx/course/presentation/container/CourseContainerTab.kt index 51d235c36..fbdbb60fc 100644 --- a/core/src/main/java/org/openedx/core/presentation/course/CourseContainerTab.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerTab.kt @@ -1,4 +1,4 @@ -package org.openedx.core.presentation.course +package org.openedx.course.presentation.container import androidx.annotation.StringRes import androidx.compose.material.icons.Icons @@ -8,17 +8,17 @@ import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.outlined.CalendarMonth import androidx.compose.material.icons.rounded.PlayCircleFilled import androidx.compose.ui.graphics.vector.ImageVector -import org.openedx.core.R import org.openedx.core.ui.TabItem +import org.openedx.course.R enum class CourseContainerTab( @StringRes override val labelResId: Int, - override val icon: ImageVector + override val icon: ImageVector, ) : TabItem { - HOME(R.string.core_course_container_nav_home, Icons.Default.Home), - VIDEOS(R.string.core_course_container_nav_videos, Icons.Rounded.PlayCircleFilled), - DATES(R.string.core_course_container_nav_dates, Icons.Outlined.CalendarMonth), - DISCUSSIONS(R.string.core_course_container_nav_discussions, Icons.AutoMirrored.Filled.Chat), - MORE(R.string.core_course_container_nav_more, Icons.AutoMirrored.Filled.TextSnippet) + HOME(R.string.course_container_nav_home, Icons.Default.Home), + VIDEOS(R.string.course_container_nav_videos, Icons.Rounded.PlayCircleFilled), + DATES(R.string.course_container_nav_dates, Icons.Outlined.CalendarMonth), + DISCUSSIONS(R.string.course_container_nav_discussions, Icons.AutoMirrored.Filled.Chat), + MORE(R.string.course_container_nav_more, Icons.AutoMirrored.Filled.TextSnippet) } 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 1ec787e54..bbc26d535 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 @@ -25,7 +25,6 @@ import org.openedx.core.config.Config import org.openedx.core.data.storage.CorePreferences import org.openedx.core.exception.NoCachedDataException import org.openedx.core.extension.isInternetError -import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType import org.openedx.core.presentation.settings.calendarsync.CalendarSyncUIState import org.openedx.core.system.CalendarManager @@ -37,8 +36,10 @@ import org.openedx.core.system.notifier.CourseCompletionSet import org.openedx.core.system.notifier.CourseDatesShifted import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier -import org.openedx.core.system.notifier.CourseRefresh +import org.openedx.core.system.notifier.CourseOpenBlock import org.openedx.core.system.notifier.CourseStructureUpdated +import org.openedx.core.system.notifier.RefreshDates +import org.openedx.core.system.notifier.RefreshDiscussions import org.openedx.core.utils.TimeUtils import org.openedx.course.DatesShiftedSnackBar import org.openedx.course.data.storage.CoursePreferences @@ -56,6 +57,7 @@ import org.openedx.core.R as CoreR class CourseContainerViewModel( val courseId: String, var courseName: String, + private var resumeBlockId: String, private val enrollmentMode: String, private val config: Config, private val interactor: CourseInteractor, @@ -67,7 +69,7 @@ class CourseContainerViewModel( private val coursePreferences: CoursePreferences, private val courseAnalytics: CourseAnalytics, private val imageProcessor: ImageProcessor, - val courseRouter: CourseRouter + val courseRouter: CourseRouter, ) : BaseViewModel() { private val _dataReady = MutableLiveData() @@ -179,6 +181,10 @@ class CourseContainerViewModel( } isReady } + if (_dataReady.value == true && resumeBlockId.isNotEmpty()) { + delay(500L) + courseNotifier.send(CourseOpenBlock(resumeBlockId)) + } } catch (e: Exception) { if (e.isInternetError() || e is NoCachedDataException) { _errorMessage.value = @@ -221,13 +227,13 @@ class CourseContainerViewModel( CourseContainerTab.DATES -> { viewModelScope.launch { - courseNotifier.send(CourseRefresh(courseContainerTab)) + courseNotifier.send(RefreshDates) } } CourseContainerTab.DISCUSSIONS -> { viewModelScope.launch { - courseNotifier.send(CourseRefresh(courseContainerTab)) + courseNotifier.send(RefreshDiscussions) } } @@ -265,7 +271,6 @@ class CourseContainerViewModel( } } - fun setCalendarSyncDialogType(dialogType: CalendarSyncDialogType) { val currentState = _calendarSyncUIState.value if (currentState.dialogType != dialogType) { diff --git a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt index 6e875d263..7381402b2 100644 --- a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt @@ -86,7 +86,6 @@ import org.openedx.core.ui.windowSizeValue 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.ui.CourseDatesBanner import org.openedx.course.presentation.ui.CourseDatesBannerTablet import java.util.concurrent.atomic.AtomicReference @@ -95,50 +94,49 @@ import org.openedx.core.R as CoreR @Composable fun CourseDatesScreen( windowSize: WindowSize, - courseDatesViewModel: CourseDatesViewModel, - courseRouter: CourseRouter, + viewModel: CourseDatesViewModel, fragmentManager: FragmentManager, isFragmentResumed: Boolean, updateCourseStructure: () -> Unit ) { - val uiState by courseDatesViewModel.uiState.observeAsState(DatesUIState.Loading) - val uiMessage by courseDatesViewModel.uiMessage.collectAsState(null) - val calendarSyncUIState by courseDatesViewModel.calendarSyncUIState.collectAsState() + val uiState by viewModel.uiState.observeAsState(DatesUIState.Loading) + val uiMessage by viewModel.uiMessage.collectAsState(null) + val calendarSyncUIState by viewModel.calendarSyncUIState.collectAsState() val context = LocalContext.current CourseDatesUI( windowSize = windowSize, uiState = uiState, uiMessage = uiMessage, - isSelfPaced = courseDatesViewModel.isSelfPaced, + isSelfPaced = viewModel.isSelfPaced, calendarSyncUIState = calendarSyncUIState, onItemClick = { block -> if (block.blockId.isNotEmpty()) { - courseDatesViewModel.getVerticalBlock(block.blockId) + viewModel.getVerticalBlock(block.blockId) ?.let { verticalBlock -> - courseDatesViewModel.logCourseComponentTapped(true, block) - if (courseDatesViewModel.isCourseExpandableSectionsEnabled) { - courseRouter.navigateToCourseContainer( + viewModel.logCourseComponentTapped(true, block) + if (viewModel.isCourseExpandableSectionsEnabled) { + viewModel.courseRouter.navigateToCourseContainer( fm = fragmentManager, - courseId = courseDatesViewModel.courseId, + courseId = viewModel.courseId, unitId = verticalBlock.id, componentId = "", mode = CourseViewMode.FULL ) } else { - courseDatesViewModel.getSequentialBlock(verticalBlock.id) + viewModel.getSequentialBlock(verticalBlock.id) ?.let { sequentialBlock -> - courseRouter.navigateToCourseSubsections( + viewModel.courseRouter.navigateToCourseSubsections( fm = fragmentManager, subSectionId = sequentialBlock.id, - courseId = courseDatesViewModel.courseId, + courseId = viewModel.courseId, unitId = verticalBlock.id, mode = CourseViewMode.FULL ) } } } ?: { - courseDatesViewModel.logCourseComponentTapped(false, block) + viewModel.logCourseComponentTapped(false, block) ActionDialogFragment.newInstance( title = context.getString(CoreR.string.core_leaving_the_app), message = context.getString( @@ -157,20 +155,20 @@ fun CourseDatesScreen( }, onPLSBannerViewed = { if (isFragmentResumed) { - courseDatesViewModel.logPlsBannerViewed() + viewModel.logPlsBannerViewed() } }, onSyncDates = { - courseDatesViewModel.logPlsShiftButtonClicked() - courseDatesViewModel.resetCourseDatesBanner { - courseDatesViewModel.logPlsShiftDates(it) + viewModel.logPlsShiftButtonClicked() + viewModel.resetCourseDatesBanner { + viewModel.logPlsShiftDates(it) if (it) { updateCourseStructure() } } }, onCalendarSyncSwitch = { isChecked -> - courseDatesViewModel.handleCalendarSyncState(isChecked) + viewModel.handleCalendarSyncState(isChecked) }, ) } 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 5d7f94d47..2591a8f3e 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 @@ -26,18 +26,18 @@ import org.openedx.core.extension.isInternetError import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType import org.openedx.core.presentation.settings.calendarsync.CalendarSyncUIState import org.openedx.core.system.CalendarManager -import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CalendarSyncEvent.CheckCalendarSyncEvent import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent import org.openedx.core.system.notifier.CourseDatesShifted import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier -import org.openedx.core.system.notifier.CourseRefresh +import org.openedx.core.system.notifier.RefreshDates import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseAnalyticsEvent import org.openedx.course.presentation.CourseAnalyticsKey +import org.openedx.course.presentation.CourseRouter import org.openedx.core.R as CoreR class CourseDatesViewModel( @@ -51,6 +51,7 @@ class CourseDatesViewModel( private val corePreferences: CorePreferences, private val courseAnalytics: CourseAnalytics, private val config: Config, + val courseRouter: CourseRouter ) : BaseViewModel() { var isSelfPaced = true @@ -86,10 +87,8 @@ class CourseDatesViewModel( _calendarSyncUIState.update { it.copy(isSynced = event.isSynced) } } - is CourseRefresh -> { - if (event.courseContainerTab == CourseContainerTab.DATES) { - loadingCourseDatesInternal() - } + is RefreshDates -> { + loadingCourseDatesInternal() } } } diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt index 3bdc9e622..9903578dc 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -61,122 +62,104 @@ 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.core.utils.FileUtil 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.course.presentation.ui.CourseExpandableChapterCard import org.openedx.course.presentation.ui.CourseMessage import org.openedx.course.presentation.ui.CourseSectionCard import org.openedx.course.presentation.ui.CourseSubSectionItem -import java.io.File import java.util.Date import org.openedx.core.R as CoreR @Composable fun CourseOutlineScreen( windowSize: WindowSize, - courseOutlineViewModel: CourseOutlineViewModel, - courseRouter: CourseRouter, + viewModel: CourseOutlineViewModel, fragmentManager: FragmentManager, onResetDatesClick: () -> Unit ) { - val uiState by courseOutlineViewModel.uiState.collectAsState() - val uiMessage by courseOutlineViewModel.uiMessage.collectAsState(null) + val uiState by viewModel.uiState.collectAsState() + val uiMessage by viewModel.uiMessage.collectAsState(null) + val resumeBlockId by viewModel.resumeBlockId.collectAsState("") val context = LocalContext.current + LaunchedEffect(resumeBlockId) { + if (resumeBlockId.isNotEmpty()) { + viewModel.openBlock(fragmentManager, resumeBlockId) + } + } + CourseOutlineUI( windowSize = windowSize, uiState = uiState, - isCourseNestedListEnabled = courseOutlineViewModel.isCourseNestedListEnabled, + isCourseNestedListEnabled = viewModel.isCourseNestedListEnabled, uiMessage = uiMessage, onItemClick = { block -> - courseOutlineViewModel.sequentialClickedEvent( + viewModel.sequentialClickedEvent( block.blockId, block.displayName ) - courseRouter.navigateToCourseSubsections( + viewModel.courseRouter.navigateToCourseSubsections( fm = fragmentManager, - courseId = courseOutlineViewModel.courseId, + courseId = viewModel.courseId, subSectionId = block.id, mode = CourseViewMode.FULL ) }, onExpandClick = { block -> - if (courseOutlineViewModel.switchCourseSections(block.id)) { - courseOutlineViewModel.sequentialClickedEvent( + if (viewModel.switchCourseSections(block.id)) { + viewModel.sequentialClickedEvent( block.blockId, block.displayName ) } }, onSubSectionClick = { subSectionBlock -> - courseOutlineViewModel.courseSubSectionUnit[subSectionBlock.id]?.let { unit -> - courseOutlineViewModel.logUnitDetailViewedEvent( + viewModel.courseSubSectionUnit[subSectionBlock.id]?.let { unit -> + viewModel.logUnitDetailViewedEvent( unit.blockId, unit.displayName ) - courseRouter.navigateToCourseContainer( + viewModel.courseRouter.navigateToCourseContainer( fragmentManager, - courseId = courseOutlineViewModel.courseId, + courseId = viewModel.courseId, unitId = unit.id, mode = CourseViewMode.FULL ) } }, onResumeClick = { componentId -> - courseOutlineViewModel.resumeSectionBlock?.let { subSection -> - courseOutlineViewModel.resumeCourseTappedEvent(subSection.id) - courseOutlineViewModel.resumeVerticalBlock?.let { unit -> - if (courseOutlineViewModel.isCourseExpandableSectionsEnabled) { - courseRouter.navigateToCourseContainer( - fm = fragmentManager, - courseId = courseOutlineViewModel.courseId, - unitId = unit.id, - componentId = componentId, - mode = CourseViewMode.FULL - ) - } else { - courseRouter.navigateToCourseSubsections( - fragmentManager, - courseId = courseOutlineViewModel.courseId, - subSectionId = subSection.id, - mode = CourseViewMode.FULL, - unitId = unit.id, - componentId = componentId - ) - } - } - } + viewModel.openBlock( + fragmentManager, + componentId + ) }, onDownloadClick = { - if (courseOutlineViewModel.isBlockDownloading(it.id)) { - courseRouter.navigateToDownloadQueue( + if (viewModel.isBlockDownloading(it.id)) { + viewModel.courseRouter.navigateToDownloadQueue( fm = fragmentManager, - courseOutlineViewModel.getDownloadableChildren(it.id) + viewModel.getDownloadableChildren(it.id) ?: arrayListOf() ) - } else if (courseOutlineViewModel.isBlockDownloaded(it.id)) { - courseOutlineViewModel.removeDownloadModels(it.id) + } else if (viewModel.isBlockDownloaded(it.id)) { + viewModel.removeDownloadModels(it.id) } else { - courseOutlineViewModel.saveDownloadModels( - context.externalCacheDir.toString() + - File.separator + - context - .getString(CoreR.string.app_name) - .replace(Regex("\\s"), "_"), it.id + viewModel.saveDownloadModels( + FileUtil(context).getExternalAppDir().path, it.id ) } }, onResetDatesClick = { - courseOutlineViewModel.resetCourseDatesBanner( + viewModel.resetCourseDatesBanner( onResetDates = { onResetDatesClick() } ) }, onCertificateClick = { - courseOutlineViewModel.viewCertificateTappedEvent() + viewModel.viewCertificateTappedEvent() it.takeIfNotEmpty() ?.let { url -> AndroidUriHandler(context).openUri(url) } } 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 306498d89..f533410b8 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 @@ -1,5 +1,6 @@ package org.openedx.course.presentation.outline +import androidx.fragment.app.FragmentManager import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -25,6 +26,7 @@ import org.openedx.core.module.DownloadWorkerController import org.openedx.core.module.db.DownloadDao import org.openedx.core.module.download.BaseDownloadViewModel import org.openedx.core.presentation.CoreAnalytics +import org.openedx.core.presentation.course.CourseViewMode import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection @@ -32,11 +34,13 @@ import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEven import org.openedx.core.system.notifier.CourseDatesShifted import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier +import org.openedx.core.system.notifier.CourseOpenBlock import org.openedx.core.system.notifier.CourseStructureUpdated import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseAnalyticsEvent import org.openedx.course.presentation.CourseAnalyticsKey +import org.openedx.course.presentation.CourseRouter import org.openedx.course.R as courseR class CourseOutlineViewModel( @@ -49,6 +53,7 @@ class CourseOutlineViewModel( private val networkConnection: NetworkConnection, private val preferencesManager: CorePreferences, private val analytics: CourseAnalytics, + val courseRouter: CourseRouter, coreAnalytics: CoreAnalytics, downloadDao: DownloadDao, workerController: DownloadWorkerController, @@ -69,12 +74,14 @@ class CourseOutlineViewModel( val uiMessage: SharedFlow get() = _uiMessage.asSharedFlow() - var resumeSectionBlock: Block? = null - private set - var resumeVerticalBlock: Block? = null - private set + private val _resumeBlockId = MutableSharedFlow() + val resumeBlockId: SharedFlow + get() = _resumeBlockId.asSharedFlow() - val isCourseExpandableSectionsEnabled get() = config.isCourseNestedListEnabled() + private var resumeSectionBlock: Block? = null + private var resumeVerticalBlock: Block? = null + + private val isCourseExpandableSectionsEnabled get() = config.isCourseNestedListEnabled() private val courseSubSections = mutableMapOf>() private val subSectionsDownloadsCount = mutableMapOf() @@ -89,6 +96,10 @@ class CourseOutlineViewModel( updateCourseData() } } + + is CourseOpenBlock -> { + _resumeBlockId.emit(event.blockId) + } } } } @@ -277,6 +288,41 @@ class CourseOutlineViewModel( } } + fun openBlock(fragmentManager: FragmentManager, blockId: String) { + viewModelScope.launch { + val courseStructure = interactor.getCourseStructure(courseId, false) + val blocks = courseStructure.blockData + getResumeBlock(blocks, blockId) + resumeBlock(fragmentManager, blockId) + } + } + + private fun resumeBlock(fragmentManager: FragmentManager, blockId: String) { + resumeSectionBlock?.let { subSection -> + resumeCourseTappedEvent(subSection.id) + resumeVerticalBlock?.let { unit -> + if (isCourseExpandableSectionsEnabled) { + courseRouter.navigateToCourseContainer( + fm = fragmentManager, + courseId = courseId, + unitId = unit.id, + componentId = blockId, + mode = CourseViewMode.FULL + ) + } else { + courseRouter.navigateToCourseSubsections( + fragmentManager, + courseId = courseId, + subSectionId = subSection.id, + mode = CourseViewMode.FULL, + unitId = unit.id, + componentId = blockId + ) + } + } + } + } + fun viewCertificateTappedEvent() { analytics.logEvent( CourseAnalyticsEvent.VIEW_CERTIFICATE.eventName, @@ -287,7 +333,7 @@ class CourseOutlineViewModel( ) } - fun resumeCourseTappedEvent(blockId: String) { + private fun resumeCourseTappedEvent(blockId: String) { val currentState = uiState.value if (currentState is CourseOutlineUIState.CourseData) { analytics.logEvent( diff --git a/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt b/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt index 297545117..6a1a1bf9e 100644 --- a/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt @@ -5,14 +5,40 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup import androidx.compose.foundation.clickable -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.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding +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.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Surface +import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close -import androidx.compose.runtime.* +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.ui.Alignment import androidx.compose.ui.Modifier @@ -40,15 +66,23 @@ import org.openedx.core.domain.model.BlockCounts import org.openedx.core.extension.serializable import org.openedx.core.module.db.DownloadedState import org.openedx.core.presentation.course.CourseViewMode -import org.openedx.core.ui.* +import org.openedx.core.ui.BackBtn +import org.openedx.core.ui.HandleUIMessage +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.statusBarsInset import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appShapes import org.openedx.core.ui.theme.appTypography +import org.openedx.core.ui.windowSizeValue +import org.openedx.core.utils.FileUtil import org.openedx.course.R import org.openedx.course.presentation.CourseRouter import org.openedx.course.presentation.ui.CardArrow -import java.io.File +import org.openedx.core.R as CoreR class CourseSectionFragment : Fragment() { @@ -100,11 +134,7 @@ class CourseSectionFragment : Fragment() { viewModel.removeDownloadModels(it.id) } else { viewModel.saveDownloadModels( - requireContext().externalCacheDir.toString() + - File.separator + - requireContext() - .getString(org.openedx.core.R.string.app_name) - .replace(Regex("\\s"), "_"), it.id + FileUtil(context).getExternalAppDir().path, it.id ) } } @@ -276,7 +306,7 @@ private fun CourseSubsectionItem( ) { val completedIconPainter = if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource( - R.drawable.ic_course_chapter_icon + CoreR.drawable.ic_core_chapter_icon ) val completedIconColor = if (block.isCompleted()) MaterialTheme.appColors.primary else MaterialTheme.appColors.onSurface 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 011003ede..10fa4ef84 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 @@ -121,7 +121,7 @@ fun CourseSectionCard( ) { val completedIconPainter = if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource( - R.drawable.ic_course_chapter_icon + coreR.drawable.ic_core_chapter_icon ) val completedIconColor = if (block.isCompleted()) MaterialTheme.appColors.primary else MaterialTheme.appColors.onSurface @@ -631,7 +631,7 @@ fun CourseSubSectionItem( ) { val icon = if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource( - R.drawable.ic_course_chapter_icon + coreR.drawable.ic_core_chapter_icon ) val iconColor = if (block.isCompleted()) MaterialTheme.appColors.primary else MaterialTheme.appColors.onSurface diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt index 30706cd6d..6e8f19610 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt @@ -76,100 +76,90 @@ 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.core.utils.FileUtil import org.openedx.course.R -import org.openedx.course.presentation.CourseRouter import org.openedx.course.presentation.videos.CourseVideoViewModel import org.openedx.course.presentation.videos.CourseVideosUIState -import java.io.File import java.util.Date @Composable fun CourseVideosScreen( windowSize: WindowSize, - courseVideoViewModel: CourseVideoViewModel, - fragmentManager: FragmentManager, - courseRouter: CourseRouter + viewModel: CourseVideoViewModel, + fragmentManager: FragmentManager ) { - val uiState by courseVideoViewModel.uiState.collectAsState(CourseVideosUIState.Loading) - val uiMessage by courseVideoViewModel.uiMessage.collectAsState(null) - val videoSettings by courseVideoViewModel.videoSettings.collectAsState() + val uiState by viewModel.uiState.collectAsState(CourseVideosUIState.Loading) + val uiMessage by viewModel.uiMessage.collectAsState(null) + val videoSettings by viewModel.videoSettings.collectAsState() val context = LocalContext.current CourseVideosUI( windowSize = windowSize, uiState = uiState, uiMessage = uiMessage, - courseTitle = courseVideoViewModel.courseTitle, - isCourseNestedListEnabled = courseVideoViewModel.isCourseNestedListEnabled, + courseTitle = viewModel.courseTitle, + isCourseNestedListEnabled = viewModel.isCourseNestedListEnabled, videoSettings = videoSettings, onItemClick = { block -> - courseRouter.navigateToCourseSubsections( + viewModel.courseRouter.navigateToCourseSubsections( fm = fragmentManager, - courseId = courseVideoViewModel.courseId, + courseId = viewModel.courseId, subSectionId = block.id, mode = CourseViewMode.VIDEOS ) }, onExpandClick = { block -> - courseVideoViewModel.switchCourseSections(block.id) + viewModel.switchCourseSections(block.id) }, onSubSectionClick = { subSectionBlock -> - courseVideoViewModel.courseSubSectionUnit[subSectionBlock.id]?.let { unit -> - courseVideoViewModel.sequentialClickedEvent( + viewModel.courseSubSectionUnit[subSectionBlock.id]?.let { unit -> + viewModel.sequentialClickedEvent( unit.blockId, unit.displayName ) - courseRouter.navigateToCourseContainer( + viewModel.courseRouter.navigateToCourseContainer( fm = fragmentManager, - courseId = courseVideoViewModel.courseId, + courseId = viewModel.courseId, unitId = unit.id, mode = CourseViewMode.VIDEOS ) } }, onDownloadClick = { - if (courseVideoViewModel.isBlockDownloading(it.id)) { - courseRouter.navigateToDownloadQueue( + if (viewModel.isBlockDownloading(it.id)) { + viewModel.courseRouter.navigateToDownloadQueue( fm = fragmentManager, - courseVideoViewModel.getDownloadableChildren(it.id) + viewModel.getDownloadableChildren(it.id) ?: arrayListOf() ) - } else if (courseVideoViewModel.isBlockDownloaded(it.id)) { - courseVideoViewModel.removeDownloadModels(it.id) + } else if (viewModel.isBlockDownloaded(it.id)) { + viewModel.removeDownloadModels(it.id) } else { - courseVideoViewModel.saveDownloadModels( - context.externalCacheDir.toString() + - File.separator + - context - .getString(org.openedx.core.R.string.app_name) - .replace(Regex("\\s"), "_"), it.id + viewModel.saveDownloadModels( + FileUtil(context).getExternalAppDir().path, it.id ) } }, onDownloadAllClick = { isAllBlocksDownloadedOrDownloading -> - courseVideoViewModel.logBulkDownloadToggleEvent(!isAllBlocksDownloadedOrDownloading) + viewModel.logBulkDownloadToggleEvent(!isAllBlocksDownloadedOrDownloading) if (isAllBlocksDownloadedOrDownloading) { - courseVideoViewModel.removeAllDownloadModels() + viewModel.removeAllDownloadModels() } else { - courseVideoViewModel.saveAllDownloadModels( - context.externalCacheDir.toString() + - File.separator + - context - .getString(org.openedx.core.R.string.app_name) - .replace(Regex("\\s"), "_") + viewModel.saveAllDownloadModels( + FileUtil(context).getExternalAppDir().path ) } }, onDownloadQueueClick = { - if (courseVideoViewModel.hasDownloadModelsInQueue()) { - courseRouter.navigateToDownloadQueue(fm = fragmentManager) + if (viewModel.hasDownloadModelsInQueue()) { + viewModel.courseRouter.navigateToDownloadQueue(fm = fragmentManager) } }, onVideoDownloadQualityClick = { - if (courseVideoViewModel.hasDownloadModelsInQueue()) { - courseVideoViewModel.onChangingVideoQualityWhileDownloading() + if (viewModel.hasDownloadModelsInQueue()) { + viewModel.onChangingVideoQualityWhileDownloading() } else { - courseRouter.navigateToVideoQuality( + viewModel.courseRouter.navigateToVideoQuality( fragmentManager, VideoQualityType.Download ) diff --git a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt index f5e9be934..b8f2e8fb1 100644 --- a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt @@ -28,6 +28,7 @@ import org.openedx.core.system.notifier.VideoQualityChanged import org.openedx.course.R import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics +import org.openedx.course.presentation.CourseRouter class CourseVideoViewModel( val courseId: String, @@ -40,6 +41,7 @@ class CourseVideoViewModel( private val courseNotifier: CourseNotifier, private val videoNotifier: VideoNotifier, private val analytics: CourseAnalytics, + val courseRouter: CourseRouter, coreAnalytics: CoreAnalytics, downloadDao: DownloadDao, workerController: DownloadWorkerController diff --git a/course/src/main/res/drawable/ic_course_chapter_icon.xml b/course/src/main/res/drawable/ic_course_chapter_icon.xml deleted file mode 100644 index eaf899ce2..000000000 --- a/course/src/main/res/drawable/ic_course_chapter_icon.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - diff --git a/course/src/main/res/values/strings.xml b/course/src/main/res/values/strings.xml index 6a974cb15..3d6e13094 100644 --- a/course/src/main/res/values/strings.xml +++ b/course/src/main/res/values/strings.xml @@ -41,6 +41,12 @@ Course dates are not currently available. + Home + Videos + Discussions + More + Dates + Video player Remove course section diff --git a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt index aff60b21e..c20bb07be 100644 --- a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt @@ -154,6 +154,7 @@ class CourseContainerViewModelTest { "", "", "", + "", config, interactor, calendarManager, @@ -187,6 +188,7 @@ class CourseContainerViewModelTest { "", "", "", + "", config, interactor, calendarManager, @@ -220,6 +222,7 @@ class CourseContainerViewModelTest { "", "", "", + "", config, interactor, calendarManager, @@ -252,6 +255,7 @@ class CourseContainerViewModelTest { "", "", "", + "", config, interactor, calendarManager, @@ -287,6 +291,7 @@ class CourseContainerViewModelTest { "", "", "", + "", config, interactor, calendarManager, @@ -317,6 +322,7 @@ class CourseContainerViewModelTest { "", "", "", + "", config, interactor, calendarManager, @@ -347,6 +353,7 @@ class CourseContainerViewModelTest { "", "", "", + "", config, interactor, calendarManager, diff --git a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt index f8715e7b3..5e2ed50a4 100644 --- a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt @@ -44,6 +44,7 @@ import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics +import org.openedx.course.presentation.CourseRouter import java.net.UnknownHostException import java.util.Date @@ -61,6 +62,7 @@ class CourseDatesViewModelTest { private val corePreferences = mockk() private val analytics = mockk() private val config = mockk() + private val courseRouter = mockk() private val openEdx = "OpenEdx" private val calendarTitle = "OpenEdx - Abc" @@ -170,7 +172,8 @@ class CourseDatesViewModelTest { resourceManager, corePreferences, analytics, - config + config, + courseRouter ) coEvery { interactor.getCourseDates(any()) } throws UnknownHostException() val message = async { @@ -198,7 +201,8 @@ class CourseDatesViewModelTest { resourceManager, corePreferences, analytics, - config + config, + courseRouter ) coEvery { interactor.getCourseDates(any()) } throws Exception() val message = async { @@ -226,7 +230,8 @@ class CourseDatesViewModelTest { resourceManager, corePreferences, analytics, - config + config, + courseRouter ) coEvery { interactor.getCourseDates(any()) } returns mockedCourseDatesResult val message = async { @@ -254,7 +259,8 @@ class CourseDatesViewModelTest { resourceManager, corePreferences, analytics, - config + config, + courseRouter ) coEvery { interactor.getCourseDates(any()) } returns CourseDatesResult( datesSection = linkedMapOf(), 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 c2b2cff57..45abb10ee 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 @@ -56,6 +56,7 @@ import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseStructureUpdated import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics +import org.openedx.course.presentation.CourseRouter import java.net.UnknownHostException import java.util.Date @@ -77,6 +78,7 @@ class CourseOutlineViewModelTest { private val workerController = mockk() private val analytics = mockk() private val coreAnalytics = mockk() + private val courseRouter = mockk() private val noInternet = "Slow or no internet connection" private val somethingWrong = "Something went wrong" @@ -233,6 +235,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController, @@ -267,6 +270,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -311,6 +315,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -358,6 +363,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -404,6 +410,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -438,6 +445,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -486,6 +494,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -529,6 +538,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -564,6 +574,7 @@ class CourseOutlineViewModelTest { networkConnection, preferencesManager, analytics, + courseRouter, coreAnalytics, downloadDao, workerController diff --git a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt index a2dae8b2e..7962011db 100644 --- a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt @@ -53,6 +53,7 @@ import org.openedx.core.system.notifier.VideoNotifier import org.openedx.course.R import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics +import org.openedx.course.presentation.CourseRouter import java.util.Date @OptIn(ExperimentalCoroutinesApi::class) @@ -73,6 +74,7 @@ class CourseVideoViewModelTest { private val networkConnection = mockk() private val downloadDao = mockk() private val workerController = mockk() + private val courseRouter = mockk() private val cantDownload = "You can download content only from Wi-fi" @@ -197,9 +199,10 @@ class CourseVideoViewModelTest { courseNotifier, videoNotifier, analytics, + courseRouter, coreAnalytics, downloadDao, - workerController + workerController, ) viewModel.getVideos() @@ -228,6 +231,7 @@ class CourseVideoViewModelTest { courseNotifier, videoNotifier, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -267,6 +271,7 @@ class CourseVideoViewModelTest { courseNotifier, videoNotifier, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -308,6 +313,7 @@ class CourseVideoViewModelTest { courseNotifier, videoNotifier, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -344,6 +350,7 @@ class CourseVideoViewModelTest { courseNotifier, videoNotifier, analytics, + courseRouter, coreAnalytics, downloadDao, workerController @@ -384,6 +391,7 @@ class CourseVideoViewModelTest { courseNotifier, videoNotifier, analytics, + courseRouter, coreAnalytics, downloadDao, workerController diff --git a/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt b/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt index dbf15acd4..f3b6a5aee 100644 --- a/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt +++ b/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt @@ -68,7 +68,7 @@ class MyCoursesScreenTest { @Test fun dashboardScreenLoading() { composeTestRule.setContent { - MyCoursesScreen( + DashboardListView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", state = DashboardUIState.Courses(listOf(mockCourseEnrolled, mockCourseEnrolled)), @@ -101,7 +101,7 @@ class MyCoursesScreenTest { @Test fun dashboardScreenLoaded() { composeTestRule.setContent { - MyCoursesScreen( + DashboardListView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", state = DashboardUIState.Courses(listOf(mockCourseEnrolled, mockCourseEnrolled)), @@ -127,7 +127,7 @@ class MyCoursesScreenTest { @Test fun dashboardScreenRefreshing() { composeTestRule.setContent { - MyCoursesScreen( + DashboardListView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", state = DashboardUIState.Courses(listOf(mockCourseEnrolled, mockCourseEnrolled)), diff --git a/dashboard/src/main/java/org/openedx/DashboardNavigator.kt b/dashboard/src/main/java/org/openedx/DashboardNavigator.kt new file mode 100644 index 000000000..9e5f4c900 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/DashboardNavigator.kt @@ -0,0 +1,17 @@ +package org.openedx + +import androidx.fragment.app.Fragment +import org.openedx.core.config.DashboardConfig +import org.openedx.dashboard.presentation.DashboardListFragment +import org.openedx.learn.presentation.LearnFragment + +class DashboardNavigator( + private val dashboardType: DashboardConfig.DashboardType, +) { + fun getDashboardFragment(): Fragment { + return when (dashboardType) { + DashboardConfig.DashboardType.GALLERY -> LearnFragment() + else -> DashboardListFragment() + } + } +} diff --git a/dashboard/src/main/java/org/openedx/DashboardUI.kt b/dashboard/src/main/java/org/openedx/DashboardUI.kt new file mode 100644 index 000000000..13a3f42d1 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/DashboardUI.kt @@ -0,0 +1,49 @@ +package org.openedx + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Lock +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors + +@Composable +fun Lock(modifier: Modifier = Modifier) { + Box( + modifier = modifier.fillMaxSize() + ) { + Icon( + modifier = Modifier + .size(32.dp) + .padding(top = 8.dp, end = 8.dp) + .background( + color = MaterialTheme.appColors.onPrimary.copy(0.5f), + shape = CircleShape + ) + .padding(4.dp) + .align(Alignment.TopEnd), + imageVector = Icons.Default.Lock, + contentDescription = null, + tint = MaterialTheme.appColors.onSurface + ) + } +} + +@Preview +@Composable +private fun LockPreview() { + OpenEdXTheme { + Lock() + } +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesAction.kt b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesAction.kt new file mode 100644 index 000000000..7655fd6a2 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesAction.kt @@ -0,0 +1,14 @@ +package org.openedx.courses.presentation + +import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.dashboard.domain.CourseStatusFilter + +interface AllEnrolledCoursesAction { + object Reload : AllEnrolledCoursesAction + object SwipeRefresh : AllEnrolledCoursesAction + object EndOfPage : AllEnrolledCoursesAction + object Back : AllEnrolledCoursesAction + object Search : AllEnrolledCoursesAction + data class OpenCourse(val enrolledCourse: EnrolledCourse) : AllEnrolledCoursesAction + data class FilterChange(val courseStatusFilter: CourseStatusFilter?) : AllEnrolledCoursesAction +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesFragment.kt b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesFragment.kt new file mode 100644 index 000000000..e59a73fde --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesFragment.kt @@ -0,0 +1,27 @@ +package org.openedx.courses.presentation + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.fragment.app.Fragment +import org.openedx.core.ui.theme.OpenEdXTheme + +class AllEnrolledCoursesFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ) = ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + OpenEdXTheme { + AllEnrolledCoursesView( + fragmentManager = requireActivity().supportFragmentManager + ) + } + } + } +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesUIState.kt b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesUIState.kt new file mode 100644 index 000000000..2d7efb51b --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesUIState.kt @@ -0,0 +1,10 @@ +package org.openedx.courses.presentation + +import org.openedx.core.domain.model.EnrolledCourse + +data class AllEnrolledCoursesUIState( + val courses: List? = null, + val refreshing: Boolean = false, + val canLoadMore: Boolean = false, + val showProgress: Boolean = false, +) diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt new file mode 100644 index 000000000..3392ed7bd --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt @@ -0,0 +1,639 @@ +package org.openedx.courses.presentation + +import android.content.res.Configuration +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.grid.rememberLazyGridState +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material.Card +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.LinearProgressIndicator +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Search +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +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.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTagsAsResourceId +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 +import androidx.fragment.app.FragmentManager +import coil.compose.AsyncImage +import coil.request.ImageRequest +import org.koin.androidx.compose.koinViewModel +import org.openedx.Lock +import org.openedx.core.R +import org.openedx.core.UIMessage +import org.openedx.core.domain.model.Certificate +import org.openedx.core.domain.model.CourseAssignments +import org.openedx.core.domain.model.CourseSharingUtmParameters +import org.openedx.core.domain.model.CourseStatus +import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.domain.model.EnrolledCourseData +import org.openedx.core.domain.model.Progress +import org.openedx.core.ui.BackBtn +import org.openedx.core.ui.HandleUIMessage +import org.openedx.core.ui.OfflineModeDialog +import org.openedx.core.ui.RoundTabsBar +import org.openedx.core.ui.displayCutoutForLandscape +import org.openedx.core.ui.rememberWindowSize +import org.openedx.core.ui.shouldLoadMore +import org.openedx.core.ui.statusBarsInset +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes +import org.openedx.core.ui.theme.appTypography +import org.openedx.core.ui.windowSizeValue +import org.openedx.core.utils.TimeUtils +import org.openedx.dashboard.domain.CourseStatusFilter +import java.util.Date + +@Composable +fun AllEnrolledCoursesView( + fragmentManager: FragmentManager +) { + val viewModel: AllEnrolledCoursesViewModel = koinViewModel() + val uiState by viewModel.uiState.collectAsState() + val uiMessage by viewModel.uiMessage.collectAsState(null) + + AllEnrolledCoursesView( + apiHostUrl = viewModel.apiHostUrl, + state = uiState, + uiMessage = uiMessage, + hasInternetConnection = viewModel.hasInternetConnection, + onAction = { action -> + when (action) { + AllEnrolledCoursesAction.Reload -> { + viewModel.getCourses() + } + + AllEnrolledCoursesAction.SwipeRefresh -> { + viewModel.updateCourses() + } + + AllEnrolledCoursesAction.EndOfPage -> { + viewModel.fetchMore() + } + + AllEnrolledCoursesAction.Back -> { + fragmentManager.popBackStack() + } + + AllEnrolledCoursesAction.Search -> { + viewModel.navigateToCourseSearch(fragmentManager) + } + + is AllEnrolledCoursesAction.OpenCourse -> { + with(action.enrolledCourse) { + viewModel.navigateToCourseOutline( + fragmentManager, + course.id, + course.name, + mode + ) + } + } + + is AllEnrolledCoursesAction.FilterChange -> { + viewModel.getCourses(action.courseStatusFilter) + } + } + } + ) +} + +@OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class) +@Composable +private fun AllEnrolledCoursesView( + apiHostUrl: String, + state: AllEnrolledCoursesUIState, + uiMessage: UIMessage?, + hasInternetConnection: Boolean, + onAction: (AllEnrolledCoursesAction) -> Unit +) { + val windowSize = rememberWindowSize() + val layoutDirection = LocalLayoutDirection.current + val scaffoldState = rememberScaffoldState() + val scrollState = rememberLazyGridState() + val columns = if (windowSize.isTablet) 3 else 2 + val pullRefreshState = rememberPullRefreshState( + refreshing = state.refreshing, + onRefresh = { onAction(AllEnrolledCoursesAction.SwipeRefresh) } + ) + val tabPagerState = rememberPagerState(pageCount = { + CourseStatusFilter.entries.size + }) + var isInternetConnectionShown by rememberSaveable { + mutableStateOf(false) + } + val firstVisibleIndex = remember { + mutableIntStateOf(scrollState.firstVisibleItemIndex) + } + + Scaffold( + scaffoldState = scaffoldState, + modifier = Modifier + .fillMaxSize() + .semantics { + testTagsAsResourceId = true + }, + backgroundColor = MaterialTheme.appColors.background + ) { paddingValues -> + val contentPaddings by remember(key1 = windowSize) { + mutableStateOf( + windowSize.windowSizeValue( + expanded = PaddingValues( + top = 16.dp, + bottom = 40.dp, + ), + compact = PaddingValues(horizontal = 16.dp, vertical = 16.dp) + ) + ) + } + + val roundTapBarPaddings by remember(key1 = windowSize) { + mutableStateOf( + windowSize.windowSizeValue( + expanded = PaddingValues(vertical = 6.dp), + compact = PaddingValues(horizontal = 16.dp, vertical = 6.dp) + ) + ) + } + + + val emptyStatePaddings by remember(key1 = windowSize) { + mutableStateOf( + windowSize.windowSizeValue( + expanded = Modifier.padding( + top = 32.dp, + bottom = 40.dp + ), + compact = Modifier.padding(horizontal = 24.dp, vertical = 24.dp) + ) + ) + } + + val contentWidth by remember(key1 = windowSize) { + mutableStateOf( + windowSize.windowSizeValue( + expanded = Modifier.widthIn(Dp.Unspecified, 650.dp), + compact = Modifier.fillMaxWidth(), + ) + ) + } + + HandleUIMessage(uiMessage = uiMessage, scaffoldState = scaffoldState) + Box( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + contentAlignment = Alignment.TopCenter + ) { + Column( + modifier = Modifier + .statusBarsInset() + .displayCutoutForLandscape() + .then(contentWidth), + horizontalAlignment = Alignment.CenterHorizontally + ) { + BackBtn( + modifier = Modifier.align(Alignment.Start), + tint = MaterialTheme.appColors.textDark + ) { + onAction(AllEnrolledCoursesAction.Back) + } + + Surface( + color = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.screenBackgroundShape + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .navigationBarsPadding() + .pullRefresh(pullRefreshState), + ) { + Column( + modifier = Modifier + .fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Header( + modifier = Modifier + .padding( + start = contentPaddings.calculateStartPadding(layoutDirection), + end = contentPaddings.calculateEndPadding(layoutDirection) + ), + onSearchClick = { + onAction(AllEnrolledCoursesAction.Search) + } + ) + RoundTabsBar( + modifier = Modifier.align(Alignment.Start), + items = CourseStatusFilter.entries, + contentPadding = roundTapBarPaddings, + rowState = rememberLazyListState(), + pagerState = tabPagerState, + onTabClicked = { + val newFilter = CourseStatusFilter.entries[it] + onAction(AllEnrolledCoursesAction.FilterChange(newFilter)) + } + ) + when { + state.showProgress -> { + Box( + modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.appColors.primary) + } + } + + !state.courses.isNullOrEmpty() -> { + Box( + modifier = Modifier + .fillMaxSize() + .padding(contentPaddings), + contentAlignment = Alignment.Center + ) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + LazyVerticalGrid( + modifier = Modifier + .fillMaxHeight(), + state = scrollState, + columns = GridCells.Fixed(columns), + verticalArrangement = Arrangement.spacedBy(12.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + content = { + items(state.courses) { course -> + CourseItem( + course = course, + apiHostUrl = apiHostUrl, + onClick = { + onAction(AllEnrolledCoursesAction.OpenCourse(it)) + } + ) + } + item { + if (state.canLoadMore) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(180.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + color = MaterialTheme.appColors.primary + ) + } + } + } + } + ) + } + if (scrollState.shouldLoadMore(firstVisibleIndex, 4)) { + onAction(AllEnrolledCoursesAction.EndOfPage) + } + } + } + + state.courses?.isEmpty() == true -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Column( + modifier = Modifier + .fillMaxHeight() + .then(emptyStatePaddings) + ) { + EmptyState( + currentCourseStatus = CourseStatusFilter.entries[tabPagerState.currentPage] + ) + } + } + } + } + } + PullRefreshIndicator( + state.refreshing, + pullRefreshState, + Modifier.align(Alignment.TopCenter) + ) + + if (!isInternetConnectionShown && !hasInternetConnection) { + OfflineModeDialog( + Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter), + onDismissCLick = { + isInternetConnectionShown = true + }, + onReloadClick = { + isInternetConnectionShown = true + onAction(AllEnrolledCoursesAction.Reload) + } + ) + } + } + } + } + } + } +} + +@Composable +fun CourseItem( + modifier: Modifier = Modifier, + course: EnrolledCourse, + apiHostUrl: String, + onClick: (EnrolledCourse) -> Unit, +) { + Card( + modifier = modifier + .width(170.dp) + .height(180.dp) + .clickable { + onClick(course) + }, + backgroundColor = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.courseImageShape, + elevation = 4.dp + ) { + Box { + Column { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(apiHostUrl + course.course.courseImage) + .error(R.drawable.core_no_image_course) + .placeholder(R.drawable.core_no_image_course) + .build(), + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxWidth() + .height(90.dp) + ) + val progress: Float = try { + course.progress.assignmentsCompleted.toFloat() / course.progress.totalAssignmentsCount.toFloat() + } catch (_: ArithmeticException) { + 0f + } + LinearProgressIndicator( + modifier = Modifier + .fillMaxWidth() + .height(8.dp), + progress = progress, + color = MaterialTheme.appColors.primary, + backgroundColor = MaterialTheme.appColors.divider + ) + + Text( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp) + .padding(top = 4.dp), + style = MaterialTheme.appTypography.labelMedium, + color = MaterialTheme.appColors.textFieldHint, + overflow = TextOverflow.Ellipsis, + minLines = 1, + maxLines = 2, + text = stringResource( + org.openedx.dashboard.R.string.dashboard_course_date, + TimeUtils.getCourseFormattedDate( + LocalContext.current, + Date(), + course.auditAccessExpires, + course.course.start, + course.course.end, + course.course.startType, + course.course.startDisplay + ) + ) + ) + Text( + modifier = Modifier + .padding(horizontal = 8.dp, vertical = 4.dp), + text = course.course.name, + style = MaterialTheme.appTypography.titleSmall, + color = MaterialTheme.appColors.textDark, + overflow = TextOverflow.Ellipsis, + minLines = 1, + maxLines = 2 + ) + } + if (!course.course.coursewareAccess?.errorCode.isNullOrEmpty()) { + Lock() + } + } + } +} + +@Composable +fun Header( + modifier: Modifier = Modifier, + onSearchClick: () -> Unit +) { + Box( + modifier = modifier.fillMaxWidth() + ) { + Text( + modifier = Modifier.align(Alignment.CenterStart), + text = stringResource(id = org.openedx.dashboard.R.string.dashboard_all_courses), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.headlineBold + ) + IconButton( + modifier = Modifier + .align(Alignment.CenterEnd) + .offset(x = 12.dp), + onClick = { + onSearchClick() + } + ) { + Icon( + imageVector = Icons.Filled.Search, + contentDescription = null, + tint = MaterialTheme.appColors.textDark + ) + } + } +} + +@Composable +fun EmptyState( + currentCourseStatus: CourseStatusFilter +) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Column( + Modifier.width(200.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + painter = painterResource(id = org.openedx.dashboard.R.drawable.dashboard_ic_book), + tint = MaterialTheme.appColors.textFieldBorder, + contentDescription = null + ) + Spacer(Modifier.height(4.dp)) + Text( + modifier = Modifier + .testTag("txt_empty_state_title") + .fillMaxWidth(), + text = stringResource( + id = org.openedx.dashboard.R.string.dashboard_no_status_courses, + stringResource(currentCourseStatus.labelResId) + ), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.titleMedium, + textAlign = TextAlign.Center + ) + } + } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun CourseItemPreview() { + OpenEdXTheme { + CourseItem( + course = mockCourseEnrolled, + apiHostUrl = "", + onClick = {} + ) + } +} + +@Preview +@Composable +private fun EmptyStatePreview() { + OpenEdXTheme { + EmptyState( + currentCourseStatus = CourseStatusFilter.COMPLETE + ) + } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@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 AllEnrolledCoursesPreview() { + OpenEdXTheme { + AllEnrolledCoursesView( + apiHostUrl = "http://localhost:8000", + state = AllEnrolledCoursesUIState( + courses = listOf( + mockCourseEnrolled, + mockCourseEnrolled, + mockCourseEnrolled, + mockCourseEnrolled, + mockCourseEnrolled, + mockCourseEnrolled + ) + ), + uiMessage = null, + hasInternetConnection = true, + onAction = {} + ) + } +} + +private val mockCourseAssignments = CourseAssignments(null, emptyList()) +private val mockCourseEnrolled = EnrolledCourse( + auditAccessExpires = Date(), + created = "created", + certificate = Certificate(""), + mode = "mode", + isActive = true, + progress = Progress.DEFAULT_PROGRESS, + courseStatus = CourseStatus("", emptyList(), "", ""), + courseAssignments = mockCourseAssignments, + course = EnrolledCourseData( + id = "id", + name = "name", + number = "", + org = "Org", + start = Date(), + startDisplay = "", + startType = "", + end = Date(), + dynamicUpgradeDeadline = "", + subscriptionId = "", + coursewareAccess = CoursewareAccess( + false, + "204", + "", + "", + "", + "" + ), + media = null, + courseImage = "", + courseAbout = "", + courseSharingUtmParameters = CourseSharingUtmParameters("", ""), + courseUpdates = "", + courseHandouts = "", + discussionUrl = "", + videoOutline = "", + isSelfPaced = false + ) +) diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesViewModel.kt b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesViewModel.kt new file mode 100644 index 000000000..6f3f96ebf --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesViewModel.kt @@ -0,0 +1,181 @@ +package org.openedx.courses.presentation + +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.openedx.core.BaseViewModel +import org.openedx.core.R +import org.openedx.core.UIMessage +import org.openedx.core.config.Config +import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.extension.isInternetError +import org.openedx.core.system.ResourceManager +import org.openedx.core.system.connection.NetworkConnection +import org.openedx.core.system.notifier.CourseDashboardUpdate +import org.openedx.core.system.notifier.DiscoveryNotifier +import org.openedx.dashboard.domain.CourseStatusFilter +import org.openedx.dashboard.domain.interactor.DashboardInteractor +import org.openedx.dashboard.presentation.DashboardAnalytics +import org.openedx.dashboard.presentation.DashboardRouter + +class AllEnrolledCoursesViewModel( + private val config: Config, + private val networkConnection: NetworkConnection, + private val interactor: DashboardInteractor, + private val resourceManager: ResourceManager, + private val discoveryNotifier: DiscoveryNotifier, + private val analytics: DashboardAnalytics, + private val dashboardRouter: DashboardRouter +) : BaseViewModel() { + + val apiHostUrl get() = config.getApiHostURL() + val hasInternetConnection: Boolean + get() = networkConnection.isOnline() + + private val coursesList = mutableListOf() + private var page = 1 + private var isLoading = false + + private val _uiState = MutableStateFlow(AllEnrolledCoursesUIState()) + val uiState: StateFlow + get() = _uiState.asStateFlow() + + private val _uiMessage = MutableSharedFlow() + val uiMessage: SharedFlow + get() = _uiMessage.asSharedFlow() + + private val currentFilter: MutableStateFlow = MutableStateFlow(CourseStatusFilter.ALL) + + private var job: Job? = null + + init { + collectDiscoveryNotifier() + getCourses(currentFilter.value) + } + + fun getCourses(courseStatusFilter: CourseStatusFilter? = null) { + _uiState.update { it.copy(showProgress = true) } + coursesList.clear() + internalLoadingCourses(courseStatusFilter ?: currentFilter.value) + } + + fun updateCourses() { + viewModelScope.launch { + try { + _uiState.update { it.copy(refreshing = true) } + isLoading = true + page = 1 + val response = interactor.getAllUserCourses(page, currentFilter.value) + if (response.pagination.next.isNotEmpty() && page != response.pagination.numPages) { + _uiState.update { it.copy(canLoadMore = true) } + page++ + } else { + _uiState.update { it.copy(canLoadMore = false) } + page = -1 + } + coursesList.clear() + coursesList.addAll(response.courses) + _uiState.update { it.copy(courses = coursesList) } + } catch (e: Exception) { + if (e.isInternetError()) { + _uiMessage.emit(UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_no_connection))) + } else { + _uiMessage.emit(UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_unknown_error))) + } + } + _uiState.update { it.copy(refreshing = false, showProgress = false) } + isLoading = false + } + } + + private fun internalLoadingCourses(courseStatusFilter: CourseStatusFilter? = null) { + if (courseStatusFilter != null) { + page = 1 + currentFilter.value = courseStatusFilter + } + job?.cancel() + job = viewModelScope.launch { + try { + isLoading = true + val response = if (networkConnection.isOnline() || page > 1) { + interactor.getAllUserCourses(page, currentFilter.value) + } else { + null + } + if (response != null) { + if (response.pagination.next.isNotEmpty() && page != response.pagination.numPages) { + _uiState.update { it.copy(canLoadMore = true) } + page++ + } else { + _uiState.update { it.copy(canLoadMore = false) } + page = -1 + } + coursesList.addAll(response.courses) + } else { + val cachedList = interactor.getEnrolledCoursesFromCache() + _uiState.update { it.copy(canLoadMore = false) } + page = -1 + coursesList.addAll(cachedList) + } + _uiState.update { it.copy(courses = coursesList) } + } catch (e: Exception) { + if (e.isInternetError()) { + _uiMessage.emit(UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_no_connection))) + } else { + _uiMessage.emit(UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_unknown_error))) + } + } + _uiState.update { it.copy(refreshing = false, showProgress = false) } + isLoading = false + } + } + + fun fetchMore() { + if (!isLoading && page != -1) { + internalLoadingCourses() + } + } + + private fun dashboardCourseClickedEvent(courseId: String, courseName: String) { + analytics.dashboardCourseClickedEvent(courseId, courseName) + } + + private fun collectDiscoveryNotifier() { + viewModelScope.launch { + discoveryNotifier.notifier.collect { + if (it is CourseDashboardUpdate) { + updateCourses() + } + } + } + } + + fun navigateToCourseSearch(fragmentManager: FragmentManager) { + dashboardRouter.navigateToCourseSearch( + fragmentManager, "" + ) + } + + fun navigateToCourseOutline( + fragmentManager: FragmentManager, + courseId: String, + courseName: String, + mode: String + ) { + dashboardCourseClickedEvent(courseId, courseName) + dashboardRouter.navigateToCourseOutline( + fragmentManager, + courseId, + courseName, + mode + ) + } +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/CourseTab.kt b/dashboard/src/main/java/org/openedx/courses/presentation/CourseTab.kt new file mode 100644 index 000000000..f0da7c186 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/CourseTab.kt @@ -0,0 +1,5 @@ +package org.openedx.courses.presentation + +enum class CourseTab { + HOME, VIDEOS, DATES, DISCUSSIONS, MORE +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryFragment.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryFragment.kt new file mode 100644 index 000000000..b0309785c --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryFragment.kt @@ -0,0 +1,24 @@ +package org.openedx.courses.presentation + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.fragment.app.Fragment +import org.openedx.core.ui.theme.OpenEdXTheme + +class DashboardGalleryFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ) = ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + OpenEdXTheme { + DashboardGalleryView(fragmentManager = requireActivity().supportFragmentManager) + } + } + } +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryScreenAction.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryScreenAction.kt new file mode 100644 index 000000000..f612a5289 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryScreenAction.kt @@ -0,0 +1,13 @@ +package org.openedx.courses.presentation + +import org.openedx.core.domain.model.EnrolledCourse + +interface DashboardGalleryScreenAction { + object SwipeRefresh : DashboardGalleryScreenAction + object ViewAll : DashboardGalleryScreenAction + object Reload : DashboardGalleryScreenAction + object NavigateToDiscovery : DashboardGalleryScreenAction + data class OpenBlock(val enrolledCourse: EnrolledCourse, val blockId: String) : DashboardGalleryScreenAction + data class OpenCourse(val enrolledCourse: EnrolledCourse) : DashboardGalleryScreenAction + data class NavigateToDates(val enrolledCourse: EnrolledCourse) : DashboardGalleryScreenAction +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryUIState.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryUIState.kt new file mode 100644 index 000000000..c4049f463 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryUIState.kt @@ -0,0 +1,9 @@ +package org.openedx.courses.presentation + +import org.openedx.core.domain.model.CourseEnrollments + +sealed class DashboardGalleryUIState { + data class Courses(val userCourses: CourseEnrollments) : DashboardGalleryUIState() + data object Empty : DashboardGalleryUIState() + data object Loading : DashboardGalleryUIState() +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt new file mode 100644 index 000000000..c4ea029b9 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt @@ -0,0 +1,863 @@ +package org.openedx.courses.presentation + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Card +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Divider +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.LinearProgressIndicator +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowForwardIos +import androidx.compose.material.icons.filled.ChevronRight +import androidx.compose.material.icons.filled.School +import androidx.compose.material.icons.filled.Warning +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +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.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +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.fragment.app.FragmentManager +import coil.compose.AsyncImage +import coil.request.ImageRequest +import org.koin.androidx.compose.koinViewModel +import org.openedx.Lock +import org.openedx.core.UIMessage +import org.openedx.core.domain.model.AppConfig +import org.openedx.core.domain.model.Certificate +import org.openedx.core.domain.model.CourseAssignments +import org.openedx.core.domain.model.CourseDateBlock +import org.openedx.core.domain.model.CourseDatesCalendarSync +import org.openedx.core.domain.model.CourseEnrollments +import org.openedx.core.domain.model.CourseSharingUtmParameters +import org.openedx.core.domain.model.CourseStatus +import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.DashboardCourseList +import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.domain.model.EnrolledCourseData +import org.openedx.core.domain.model.Pagination +import org.openedx.core.domain.model.Progress +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.rememberWindowSize +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes +import org.openedx.core.ui.theme.appTypography +import org.openedx.core.utils.TimeUtils +import org.openedx.dashboard.R +import java.util.Date +import org.openedx.core.R as CoreR + +@Composable +fun DashboardGalleryView( + fragmentManager: FragmentManager, +) { + val viewModel: DashboardGalleryViewModel = koinViewModel() + val updating by viewModel.updating.collectAsState(false) + val uiMessage by viewModel.uiMessage.collectAsState(null) + val uiState by viewModel.uiState.collectAsState(DashboardGalleryUIState.Loading) + + DashboardGalleryView( + uiMessage = uiMessage, + uiState = uiState, + updating = updating, + apiHostUrl = viewModel.apiHostUrl, + hasInternetConnection = viewModel.hasInternetConnection, + onAction = { action -> + when (action) { + DashboardGalleryScreenAction.SwipeRefresh -> { + viewModel.updateCourses() + } + + DashboardGalleryScreenAction.ViewAll -> { + viewModel.navigateToAllEnrolledCourses(fragmentManager) + } + + DashboardGalleryScreenAction.Reload -> { + viewModel.getCourses() + } + + DashboardGalleryScreenAction.NavigateToDiscovery -> { + viewModel.navigateToDiscovery() + } + + is DashboardGalleryScreenAction.OpenCourse -> { + viewModel.navigateToCourseOutline( + fragmentManager = fragmentManager, + enrolledCourse = action.enrolledCourse + ) + } + + is DashboardGalleryScreenAction.NavigateToDates -> { + viewModel.navigateToCourseOutline( + fragmentManager = fragmentManager, + enrolledCourse = action.enrolledCourse, + openDates = true + ) + } + + is DashboardGalleryScreenAction.OpenBlock -> { + viewModel.navigateToCourseOutline( + fragmentManager = fragmentManager, + enrolledCourse = action.enrolledCourse, + resumeBlockId = action.blockId + ) + } + } + } + ) +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +private fun DashboardGalleryView( + uiMessage: UIMessage?, + uiState: DashboardGalleryUIState, + updating: Boolean, + apiHostUrl: String, + onAction: (DashboardGalleryScreenAction) -> Unit, + hasInternetConnection: Boolean +) { + val scaffoldState = rememberScaffoldState() + val pullRefreshState = rememberPullRefreshState( + refreshing = updating, + onRefresh = { onAction(DashboardGalleryScreenAction.SwipeRefresh) } + ) + var isInternetConnectionShown by rememberSaveable { + mutableStateOf(false) + } + + Scaffold( + scaffoldState = scaffoldState, + modifier = Modifier.fillMaxSize(), + backgroundColor = MaterialTheme.appColors.background + ) { paddingValues -> + + HandleUIMessage(uiMessage = uiMessage, scaffoldState = scaffoldState) + + Surface( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + color = MaterialTheme.appColors.background + ) { + Box( + Modifier.fillMaxSize() + ) { + Box( + Modifier + .fillMaxSize() + .pullRefresh(pullRefreshState) + .verticalScroll(rememberScrollState()), + ) { + when (uiState) { + is DashboardGalleryUIState.Loading -> { + CircularProgressIndicator( + modifier = Modifier.align(Alignment.Center), + color = MaterialTheme.appColors.primary + ) + } + + is DashboardGalleryUIState.Courses -> { + UserCourses( + modifier = Modifier.fillMaxSize(), + userCourses = uiState.userCourses, + apiHostUrl = apiHostUrl, + openCourse = { + onAction(DashboardGalleryScreenAction.OpenCourse(it)) + }, + onViewAllClick = { + onAction(DashboardGalleryScreenAction.ViewAll) + }, + navigateToDates = { + onAction(DashboardGalleryScreenAction.NavigateToDates(it)) + }, + resumeBlockId = { course, blockId -> + onAction(DashboardGalleryScreenAction.OpenBlock(course, blockId)) + } + ) + } + + is DashboardGalleryUIState.Empty -> { + NoCoursesInfo( + modifier = Modifier + .align(Alignment.Center) + ) + FindACourseButton( + modifier = Modifier + .align(Alignment.BottomCenter), + findACourseClick = { + onAction(DashboardGalleryScreenAction.NavigateToDiscovery) + } + ) + } + } + + PullRefreshIndicator( + updating, + pullRefreshState, + Modifier.align(Alignment.TopCenter) + ) + } + if (!isInternetConnectionShown && !hasInternetConnection) { + OfflineModeDialog( + Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter), + onDismissCLick = { + isInternetConnectionShown = true + }, + onReloadClick = { + isInternetConnectionShown = true + onAction(DashboardGalleryScreenAction.SwipeRefresh) + } + ) + } + } + } + } +} + +@Composable +private fun UserCourses( + modifier: Modifier = Modifier, + userCourses: CourseEnrollments, + apiHostUrl: String, + openCourse: (EnrolledCourse) -> Unit, + navigateToDates: (EnrolledCourse) -> Unit, + onViewAllClick: () -> Unit, + resumeBlockId: (enrolledCourse: EnrolledCourse, blockId: String) -> Unit, +) { + Column( + modifier = modifier + .padding(vertical = 12.dp) + ) { + val primaryCourse = userCourses.primary + if (primaryCourse != null) { + PrimaryCourseCard( + primaryCourse = primaryCourse, + apiHostUrl = apiHostUrl, + navigateToDates = navigateToDates, + resumeBlockId = resumeBlockId, + openCourse = openCourse + ) + } + if (userCourses.enrollments.courses.isNotEmpty()) { + SecondaryCourses( + courses = userCourses.enrollments.courses, + apiHostUrl = apiHostUrl, + onCourseClick = openCourse, + onViewAllClick = onViewAllClick + ) + } + } +} + +@Composable +private fun SecondaryCourses( + courses: List, + apiHostUrl: String, + onCourseClick: (EnrolledCourse) -> Unit, + onViewAllClick: () -> Unit +) { + val windowSize = rememberWindowSize() + val itemsCount = if (windowSize.isTablet) 7 else 5 + val rows = if (windowSize.isTablet) 2 else 1 + val height = if (windowSize.isTablet) 322.dp else 152.dp + val items = courses.take(itemsCount) + Column( + modifier = Modifier + .fillMaxSize() + .padding(top = 12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + TextIcon( + modifier = Modifier.padding(horizontal = 18.dp), + text = stringResource(R.string.dashboard_view_all_with_count, courses.size + 1), + textStyle = MaterialTheme.appTypography.titleSmall, + icon = Icons.Default.ChevronRight, + color = MaterialTheme.appColors.textDark, + iconModifier = Modifier.size(22.dp), + onClick = onViewAllClick + ) + LazyHorizontalGrid( + modifier = Modifier + .fillMaxSize() + .height(height), + rows = GridCells.Fixed(rows), + contentPadding = PaddingValues(horizontal = 18.dp), + content = { + items(items) { + CourseListItem( + course = it, + apiHostUrl = apiHostUrl, + onCourseClick = onCourseClick + ) + } + item { + ViewAllItem( + onViewAllClick = onViewAllClick + ) + } + } + ) + } +} + +@Composable +private fun ViewAllItem( + onViewAllClick: () -> Unit +) { + Card( + modifier = Modifier + .width(140.dp) + .height(152.dp) + .padding(4.dp) + .clickable( + onClickLabel = stringResource(id = R.string.dashboard_view_all), + onClick = { + onViewAllClick() + } + ), + backgroundColor = MaterialTheme.appColors.cardViewBackground, + shape = MaterialTheme.appShapes.courseImageShape, + elevation = 4.dp, + ) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Icon( + modifier = Modifier.size(48.dp), + painter = painterResource(id = R.drawable.dashboard_ic_book), + tint = MaterialTheme.appColors.textFieldBorder, + contentDescription = null + ) + Spacer(modifier = Modifier.height(12.dp)) + Text( + text = stringResource(id = R.string.dashboard_view_all), + style = MaterialTheme.appTypography.titleSmall, + color = MaterialTheme.appColors.textDark + ) + } + } +} + +@Composable +private fun CourseListItem( + course: EnrolledCourse, + apiHostUrl: String, + onCourseClick: (EnrolledCourse) -> Unit, +) { + Card( + modifier = Modifier + .width(140.dp) + .height(152.dp) + .padding(4.dp) + .clickable { + onCourseClick(course) + }, + backgroundColor = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.courseImageShape, + elevation = 4.dp + ) { + Box { + Column { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(apiHostUrl + course.course.courseImage) + .error(CoreR.drawable.core_no_image_course) + .placeholder(CoreR.drawable.core_no_image_course) + .build(), + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxWidth() + .height(90.dp) + ) + Text( + modifier = Modifier + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp), + text = course.course.name, + style = MaterialTheme.appTypography.titleSmall, + color = MaterialTheme.appColors.textDark, + overflow = TextOverflow.Ellipsis, + maxLines = 2, + minLines = 2 + ) + } + if (!course.course.coursewareAccess?.errorCode.isNullOrEmpty()) { + Lock() + } + } + } +} + +@Composable +private fun AssignmentItem( + modifier: Modifier = Modifier, + painter: Painter, + title: String?, + info: String +) { + Row( + modifier = modifier + .fillMaxWidth() + .heightIn(min = 62.dp) + .padding(vertical = 12.dp, horizontal = 14.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painter, + tint = MaterialTheme.appColors.textDark, + contentDescription = null + ) + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + val infoTextStyle = if (title.isNullOrEmpty()) { + MaterialTheme.appTypography.titleSmall + } else { + MaterialTheme.appTypography.labelSmall + } + Text( + text = info, + color = MaterialTheme.appColors.textDark, + style = infoTextStyle + ) + if (!title.isNullOrEmpty()) { + Text( + text = title, + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.titleSmall + ) + } + } + Icon( + modifier = Modifier.size(16.dp), + imageVector = Icons.AutoMirrored.Filled.ArrowForwardIos, + tint = MaterialTheme.appColors.textDark, + contentDescription = null + ) + } +} + +@Composable +private fun PrimaryCourseCard( + primaryCourse: EnrolledCourse, + apiHostUrl: String, + navigateToDates: (EnrolledCourse) -> Unit, + resumeBlockId: (enrolledCourse: EnrolledCourse, blockId: String) -> Unit, + openCourse: (EnrolledCourse) -> Unit, +) { + val context = LocalContext.current + Card( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth() + .padding(2.dp), + backgroundColor = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.courseImageShape, + elevation = 4.dp + ) { + Column( + modifier = Modifier + .clickable { + openCourse(primaryCourse) + } + ) { + AsyncImage( + model = ImageRequest.Builder(context) + .data(apiHostUrl + primaryCourse.course.courseImage) + .error(CoreR.drawable.core_no_image_course) + .placeholder(CoreR.drawable.core_no_image_course) + .build(), + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxWidth() + .height(140.dp) + ) + val progress: Float = try { + primaryCourse.progress.assignmentsCompleted.toFloat() / primaryCourse.progress.totalAssignmentsCount.toFloat() + } catch (_: ArithmeticException) { + 0f + } + LinearProgressIndicator( + modifier = Modifier + .fillMaxWidth() + .height(8.dp), + progress = progress, + color = MaterialTheme.appColors.primary, + backgroundColor = MaterialTheme.appColors.divider + ) + PrimaryCourseTitle( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp) + .padding(top = 8.dp, bottom = 16.dp), + primaryCourse = primaryCourse + ) + val pastAssignments = primaryCourse.courseAssignments?.pastAssignments + if (!pastAssignments.isNullOrEmpty()) { + val nearestAssignment = pastAssignments.maxBy { it.date } + val title = if (pastAssignments.size == 1) nearestAssignment.title else null + Divider() + AssignmentItem( + modifier = Modifier.clickable { + if (pastAssignments.size == 1) { + resumeBlockId(primaryCourse, nearestAssignment.blockId) + } else { + navigateToDates(primaryCourse) + } + }, + painter = rememberVectorPainter(Icons.Default.Warning), + title = title, + info = stringResource(R.string.dashboard_past_due_assignment, pastAssignments.size) + ) + } + val futureAssignments = primaryCourse.courseAssignments?.futureAssignments + if (!futureAssignments.isNullOrEmpty()) { + val nearestAssignment = futureAssignments.minBy { it.date } + val title = if (futureAssignments.size == 1) nearestAssignment.title else null + Divider() + AssignmentItem( + modifier = Modifier.clickable { + if (futureAssignments.size == 1) { + resumeBlockId(primaryCourse, nearestAssignment.blockId) + } else { + navigateToDates(primaryCourse) + } + }, + painter = painterResource(id = CoreR.drawable.ic_core_chapter_icon), + title = title, + info = stringResource( + R.string.dashboard_assignment_due_in_days, + nearestAssignment.assignmentType ?: "", + TimeUtils.getCourseFormattedDate(context, nearestAssignment.date) + ) + ) + } + ResumeButton( + primaryCourse = primaryCourse, + onClick = { + if (primaryCourse.courseStatus == null) { + openCourse(primaryCourse) + } else { + resumeBlockId(primaryCourse, primaryCourse.courseStatus?.lastVisitedBlockId ?: "") + } + } + ) + } + } +} + +@Composable +private fun ResumeButton( + modifier: Modifier = Modifier, + primaryCourse: EnrolledCourse, + onClick: () -> Unit +) { + Row( + modifier = modifier + .fillMaxWidth() + .clickable { onClick() } + .heightIn(min = 60.dp) + .background(MaterialTheme.appColors.primary) + .padding(12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + if (primaryCourse.courseStatus == null) { + Icon( + imageVector = Icons.Default.School, + tint = MaterialTheme.appColors.primaryButtonText, + contentDescription = null + ) + Text( + modifier = Modifier.weight(1f), + text = stringResource(R.string.dashboard_start_course), + color = MaterialTheme.appColors.primaryButtonText, + style = MaterialTheme.appTypography.titleSmall + ) + } else { + Icon( + imageVector = Icons.Default.School, + tint = MaterialTheme.appColors.primaryButtonText, + contentDescription = null + ) + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(2.dp) + ) { + Text( + text = stringResource(R.string.dashboard_resume_course), + color = MaterialTheme.appColors.primaryButtonText, + style = MaterialTheme.appTypography.labelSmall + ) + Text( + text = primaryCourse.courseStatus?.lastVisitedUnitDisplayName ?: "", + color = MaterialTheme.appColors.primaryButtonText, + style = MaterialTheme.appTypography.titleSmall + ) + } + } + Icon( + modifier = Modifier.size(16.dp), + imageVector = Icons.AutoMirrored.Filled.ArrowForwardIos, + tint = MaterialTheme.appColors.primaryButtonText, + contentDescription = null + ) + } +} + +@Composable +private fun PrimaryCourseTitle( + modifier: Modifier = Modifier, + primaryCourse: EnrolledCourse +) { + Column( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + modifier = Modifier.fillMaxWidth(), + text = primaryCourse.course.org, + style = MaterialTheme.appTypography.labelMedium, + color = MaterialTheme.appColors.textFieldHint + ) + Text( + modifier = Modifier.fillMaxWidth(), + text = primaryCourse.course.name, + style = MaterialTheme.appTypography.titleLarge, + color = MaterialTheme.appColors.textDark, + overflow = TextOverflow.Ellipsis, + maxLines = 3 + ) + Text( + modifier = Modifier.fillMaxWidth(), + style = MaterialTheme.appTypography.labelMedium, + color = MaterialTheme.appColors.textFieldHint, + text = stringResource( + R.string.dashboard_course_date, + TimeUtils.getCourseFormattedDate( + LocalContext.current, + Date(), + primaryCourse.auditAccessExpires, + primaryCourse.course.start, + primaryCourse.course.end, + primaryCourse.course.startType, + primaryCourse.course.startDisplay + ) + ) + ) + } +} + +@Composable +private fun FindACourseButton( + modifier: Modifier = Modifier, + findACourseClick: () -> Unit +) { + OpenEdXButton( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 8.dp, vertical = 20.dp), + onClick = { + findACourseClick() + } + ) { + Text( + color = MaterialTheme.appColors.primaryButtonText, + text = stringResource(id = R.string.dashboard_find_a_course) + ) + } +} + +@Composable +private fun NoCoursesInfo( + modifier: Modifier = Modifier +) { + Box( + modifier = modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Column( + modifier = Modifier.width(200.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + painter = painterResource(id = R.drawable.dashboard_ic_book), + tint = MaterialTheme.appColors.textFieldBorder, + contentDescription = null + ) + Spacer(Modifier.height(4.dp)) + Text( + modifier = Modifier + .testTag("txt_empty_state_title") + .fillMaxWidth(), + text = stringResource(id = R.string.dashboard_all_courses_empty_title), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.titleMedium, + textAlign = TextAlign.Center + ) + Spacer(Modifier.height(12.dp)) + Text( + modifier = Modifier + .testTag("txt_empty_state_description") + .fillMaxWidth(), + text = stringResource(id = R.string.dashboard_all_courses_empty_description), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.labelMedium, + textAlign = TextAlign.Center + ) + } + } +} + +private val mockCourseDateBlock = CourseDateBlock( + title = "Homework 1: ABCD", + description = "After this date, course content will be archived", + date = TimeUtils.iso8601ToDate("2023-10-20T15:08:07Z")!!, + assignmentType = "Homework" +) +private val mockCourseAssignments = + CourseAssignments(listOf(mockCourseDateBlock), listOf(mockCourseDateBlock, mockCourseDateBlock)) +private val mockCourse = EnrolledCourse( + auditAccessExpires = Date(), + created = "created", + certificate = Certificate(""), + mode = "mode", + isActive = true, + progress = Progress.DEFAULT_PROGRESS, + courseStatus = CourseStatus("", emptyList(), "", "Unit name"), + courseAssignments = mockCourseAssignments, + course = EnrolledCourseData( + id = "id", + name = "Looooooooooooooooooooong Course name", + number = "", + org = "Org", + start = Date(), + startDisplay = "", + startType = "", + end = Date(), + dynamicUpgradeDeadline = "", + subscriptionId = "", + coursewareAccess = CoursewareAccess( + true, + "", + "", + "", + "", + "", + ), + media = null, + courseImage = "", + courseAbout = "", + courseSharingUtmParameters = CourseSharingUtmParameters("", ""), + courseUpdates = "", + courseHandouts = "", + discussionUrl = "", + videoOutline = "", + isSelfPaced = false + ) +) +private val mockPagination = Pagination(10, "", 4, "1") +private val mockDashboardCourseList = DashboardCourseList( + pagination = mockPagination, + courses = listOf(mockCourse, mockCourse, mockCourse, mockCourse, mockCourse, mockCourse) +) + +private val mockUserCourses = CourseEnrollments( + enrollments = mockDashboardCourseList, + configs = AppConfig(CourseDatesCalendarSync(true, true, true, true)), + primary = mockCourse +) + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ViewAllItemPreview() { + OpenEdXTheme { + ViewAllItem( + onViewAllClick = {} + ) + } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@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 DashboardGalleryViewPreview() { + OpenEdXTheme { + DashboardGalleryView( + uiState = DashboardGalleryUIState.Courses(mockUserCourses), + apiHostUrl = "", + uiMessage = null, + updating = false, + hasInternetConnection = false, + onAction = {} + ) + } +} + +@Preview +@Composable +private fun NoCoursesInfoPreview() { + OpenEdXTheme { + NoCoursesInfo() + } +} diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt new file mode 100644 index 000000000..6ff7ba3fd --- /dev/null +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt @@ -0,0 +1,130 @@ +package org.openedx.courses.presentation + +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import org.openedx.core.BaseViewModel +import org.openedx.core.R +import org.openedx.core.UIMessage +import org.openedx.core.config.Config +import org.openedx.core.data.model.CourseEnrollments +import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.extension.isInternetError +import org.openedx.core.system.ResourceManager +import org.openedx.core.system.connection.NetworkConnection +import org.openedx.core.system.notifier.CourseDashboardUpdate +import org.openedx.core.system.notifier.DiscoveryNotifier +import org.openedx.core.system.notifier.NavigationToDiscovery +import org.openedx.core.utils.FileUtil +import org.openedx.dashboard.domain.interactor.DashboardInteractor +import org.openedx.dashboard.presentation.DashboardRouter + +class DashboardGalleryViewModel( + private val config: Config, + private val interactor: DashboardInteractor, + private val resourceManager: ResourceManager, + private val discoveryNotifier: DiscoveryNotifier, + private val networkConnection: NetworkConnection, + private val fileUtil: FileUtil, + private val dashboardRouter: DashboardRouter, +) : BaseViewModel() { + + val apiHostUrl get() = config.getApiHostURL() + + private val _uiState = + MutableStateFlow(DashboardGalleryUIState.Loading) + val uiState: StateFlow + get() = _uiState.asStateFlow() + + private val _uiMessage = MutableSharedFlow() + val uiMessage: SharedFlow + get() = _uiMessage.asSharedFlow() + + private val _updating = MutableStateFlow(false) + val updating: StateFlow + get() = _updating.asStateFlow() + + val hasInternetConnection: Boolean + get() = networkConnection.isOnline() + + init { + collectDiscoveryNotifier() + getCourses() + } + + fun getCourses() { + viewModelScope.launch { + try { + if (networkConnection.isOnline()) { + val response = interactor.getMainUserCourses() + if (response.primary == null && response.enrollments.courses.isEmpty()) { + _uiState.value = DashboardGalleryUIState.Empty + } else { + _uiState.value = DashboardGalleryUIState.Courses(response) + } + } else { + val courseEnrollments = fileUtil.getObjectFromFile() + if (courseEnrollments == null) { + _uiState.value = DashboardGalleryUIState.Empty + } else { + _uiState.value = + DashboardGalleryUIState.Courses(courseEnrollments.mapToDomain()) + } + } + } catch (e: Exception) { + if (e.isInternetError()) { + _uiMessage.emit(UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_no_connection))) + } else { + _uiMessage.emit(UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_unknown_error))) + } + } finally { + _updating.value = false + } + } + } + + fun updateCourses() { + _updating.value = true + getCourses() + } + + fun navigateToDiscovery() { + viewModelScope.launch { discoveryNotifier.send(NavigationToDiscovery()) } + } + + fun navigateToAllEnrolledCourses(fragmentManager: FragmentManager) { + dashboardRouter.navigateToAllEnrolledCourses(fragmentManager) + } + + fun navigateToCourseOutline( + fragmentManager: FragmentManager, + enrolledCourse: EnrolledCourse, + openDates: Boolean = false, + resumeBlockId: String = "", + ) { + dashboardRouter.navigateToCourseOutline( + fm = fragmentManager, + courseId = enrolledCourse.course.id, + courseTitle = enrolledCourse.course.name, + enrollmentMode = enrolledCourse.mode, + openTab = if (openDates) CourseTab.DATES.name else CourseTab.HOME.name, + resumeBlockId = resumeBlockId + ) + } + + private fun collectDiscoveryNotifier() { + viewModelScope.launch { + discoveryNotifier.notifier.collect { + if (it is CourseDashboardUpdate) { + updateCourses() + } + } + } + } +} diff --git a/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt b/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt index c85390fa1..22637f48c 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt @@ -2,14 +2,18 @@ package org.openedx.dashboard.data.repository import org.openedx.core.data.api.CourseApi import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.model.CourseEnrollments import org.openedx.core.domain.model.DashboardCourseList import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.utils.FileUtil import org.openedx.dashboard.data.DashboardDao +import org.openedx.dashboard.domain.CourseStatusFilter class DashboardRepository( private val api: CourseApi, private val dao: DashboardDao, - private val preferencesManager: CorePreferences + private val preferencesManager: CorePreferences, + private val fileUtil: FileUtil, ) { suspend fun getEnrolledCourses(page: Int): DashboardCourseList { @@ -30,4 +34,30 @@ class DashboardRepository( val list = dao.readAllData() return list.map { it.mapToDomain() } } + + suspend fun getMainUserCourses(): CourseEnrollments { + val result = api.getUserCourses( + username = preferencesManager.user?.username ?: "", + ) + preferencesManager.appConfig = result.configs.mapToDomain() + + fileUtil.saveObjectToFile(result) + return result.mapToDomain() + } + + suspend fun getAllUserCourses(page: Int, status: CourseStatusFilter?): DashboardCourseList { + val user = preferencesManager.user + val result = api.getUserCourses( + username = user?.username ?: "", + page = page, + status = status?.key, + fields = listOf("course_progress") + ) + preferencesManager.appConfig = result.configs.mapToDomain() + + dao.clearCachedData() + dao.insertEnrolledCourseEntity(*result.enrollments.results.map { it.mapToRoomEntity() } + .toTypedArray()) + return result.enrollments.mapToDomain() + } } diff --git a/dashboard/src/main/java/org/openedx/dashboard/domain/CourseStatusFilter.kt b/dashboard/src/main/java/org/openedx/dashboard/domain/CourseStatusFilter.kt new file mode 100644 index 000000000..79a19b89d --- /dev/null +++ b/dashboard/src/main/java/org/openedx/dashboard/domain/CourseStatusFilter.kt @@ -0,0 +1,18 @@ +package org.openedx.dashboard.domain + +import androidx.annotation.StringRes +import androidx.compose.ui.graphics.vector.ImageVector +import org.openedx.core.ui.TabItem +import org.openedx.dashboard.R + +enum class CourseStatusFilter( + val key: String, + @StringRes + override val labelResId: Int, + override val icon: ImageVector? = null, +) : TabItem { + ALL("all", R.string.dashboard_course_filter_all), + IN_PROGRESS("in_progress", R.string.dashboard_course_filter_in_progress), + COMPLETE("completed", R.string.dashboard_course_filter_completed), + EXPIRED("expired", R.string.dashboard_course_filter_expired) +} diff --git a/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt b/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt index a29c2cc7e..ae2e94d93 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt @@ -2,9 +2,10 @@ package org.openedx.dashboard.domain.interactor import org.openedx.core.domain.model.DashboardCourseList import org.openedx.dashboard.data.repository.DashboardRepository +import org.openedx.dashboard.domain.CourseStatusFilter class DashboardInteractor( - private val repository: DashboardRepository + private val repository: DashboardRepository, ) { suspend fun getEnrolledCourses(page: Int): DashboardCourseList { @@ -12,4 +13,16 @@ class DashboardInteractor( } suspend fun getEnrolledCoursesFromCache() = repository.getEnrolledCoursesFromCache() -} \ No newline at end of file + + suspend fun getMainUserCourses() = repository.getMainUserCourses() + + suspend fun getAllUserCourses( + page: Int = 1, + status: CourseStatusFilter? = null, + ): DashboardCourseList { + return repository.getAllUserCourses( + page, + status + ) + } +} diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt similarity index 97% rename from dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardFragment.kt rename to dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index f6bc5c56a..597958e51 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -73,10 +73,13 @@ import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.core.AppUpdateState import org.openedx.core.UIMessage import org.openedx.core.domain.model.Certificate +import org.openedx.core.domain.model.CourseAssignments import org.openedx.core.domain.model.CourseSharingUtmParameters +import org.openedx.core.domain.model.CourseStatus import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.EnrolledCourse import org.openedx.core.domain.model.EnrolledCourseData +import org.openedx.core.domain.model.Progress import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRecommendedBox import org.openedx.core.system.notifier.AppUpgradeEvent import org.openedx.core.ui.HandleUIMessage @@ -98,9 +101,9 @@ import org.openedx.dashboard.R import java.util.Date import org.openedx.core.R as CoreR -class DashboardFragment : Fragment() { +class DashboardListFragment : Fragment() { - private val viewModel by viewModel() + private val viewModel by viewModel() private val router by inject() override fun onCreate(savedInstanceState: Bundle?) { @@ -123,7 +126,7 @@ class DashboardFragment : Fragment() { val canLoadMore by viewModel.canLoadMore.observeAsState(false) val appUpgradeEvent by viewModel.appUpgradeEvent.observeAsState() - MyCoursesScreen( + DashboardListView( windowSize = windowSize, viewModel.apiHostUrl, uiState!!, @@ -166,7 +169,7 @@ class DashboardFragment : Fragment() { @OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class) @Composable -internal fun MyCoursesScreen( +internal fun DashboardListView( windowSize: WindowSize, apiHostUrl: String, state: DashboardUIState, @@ -551,9 +554,9 @@ private fun CourseItemPreview() { @Preview(uiMode = UI_MODE_NIGHT_NO) @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable -private fun MyCoursesScreenDay() { +private fun DashboardListViewPreview() { OpenEdXTheme { - MyCoursesScreen( + DashboardListView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", state = DashboardUIState.Courses( @@ -583,9 +586,9 @@ private fun MyCoursesScreenDay() { @Preview(uiMode = UI_MODE_NIGHT_NO, device = Devices.NEXUS_9) @Preview(uiMode = UI_MODE_NIGHT_YES, device = Devices.NEXUS_9) @Composable -private fun MyCoursesScreenTabletPreview() { +private fun DashboardListViewTabletPreview() { OpenEdXTheme { - MyCoursesScreen( + DashboardListView( windowSize = WindowSize(WindowType.Medium, WindowType.Medium), apiHostUrl = "http://localhost:8000", state = DashboardUIState.Courses( @@ -612,12 +615,16 @@ private fun MyCoursesScreenTabletPreview() { } } +private val mockCourseAssignments = CourseAssignments(null, emptyList()) private val mockCourseEnrolled = EnrolledCourse( auditAccessExpires = Date(), created = "created", certificate = Certificate(""), mode = "mode", isActive = true, + progress = Progress.DEFAULT_PROGRESS, + courseStatus = CourseStatus("", emptyList(), "", ""), + courseAssignments = mockCourseAssignments, course = EnrolledCourseData( id = "id", name = "name", diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardViewModel.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt similarity index 99% rename from dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardViewModel.kt rename to dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt index 0ec06a2c3..812e52f2e 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardViewModel.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt @@ -20,8 +20,7 @@ import org.openedx.core.system.notifier.CourseDashboardUpdate import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.dashboard.domain.interactor.DashboardInteractor - -class DashboardViewModel( +class DashboardListViewModel( private val config: Config, private val networkConnection: NetworkConnection, private val interactor: DashboardInteractor, diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt index b0b0740d3..4d9b5cdbc 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt @@ -1,5 +1,6 @@ package org.openedx.dashboard.presentation +import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager interface DashboardRouter { @@ -9,7 +10,15 @@ interface DashboardRouter { courseId: String, courseTitle: String, enrollmentMode: String, + openTab: String = "", + resumeBlockId: String = "" ) fun navigateToSettings(fm: FragmentManager) + + fun navigateToCourseSearch(fm: FragmentManager, querySearch: String) + + fun navigateToAllEnrolledCourses(fm: FragmentManager) + + fun getProgramFragmentInstance(): Fragment } diff --git a/dashboard/src/main/java/org/openedx/learn/LearnType.kt b/dashboard/src/main/java/org/openedx/learn/LearnType.kt new file mode 100644 index 000000000..08100ef35 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/learn/LearnType.kt @@ -0,0 +1,9 @@ +package org.openedx.learn + +import androidx.annotation.StringRes +import org.openedx.dashboard.R + +enum class LearnType(@StringRes val title: Int) { + COURSES(R.string.dashboard_courses), + PROGRAMS(R.string.dashboard_programs) +} diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt new file mode 100644 index 000000000..b2de66cd4 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt @@ -0,0 +1,274 @@ +package org.openedx.learn.presentation + +import android.os.Bundle +import android.view.View +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ExpandMore +import androidx.compose.material.icons.filled.ManageAccounts +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.viewpager2.widget.ViewPager2 +import org.koin.android.ext.android.inject +import org.koin.androidx.compose.koinViewModel +import org.openedx.core.adapter.NavigationFragmentAdapter +import org.openedx.core.presentation.global.viewBinding +import org.openedx.core.ui.crop +import org.openedx.core.ui.displayCutoutForLandscape +import org.openedx.core.ui.rememberWindowSize +import org.openedx.core.ui.statusBarsInset +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.courses.presentation.DashboardGalleryFragment +import org.openedx.dashboard.R +import org.openedx.dashboard.databinding.FragmentLearnBinding +import org.openedx.dashboard.presentation.DashboardRouter +import org.openedx.learn.LearnType +import org.openedx.core.R as CoreR + +class LearnFragment : Fragment(R.layout.fragment_learn) { + + private val binding by viewBinding(FragmentLearnBinding::bind) + private val router by inject() + private lateinit var adapter: NavigationFragmentAdapter + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.header.setContent { + OpenEdXTheme { + Header( + fragmentManager = requireParentFragment().parentFragmentManager, + viewPager = binding.viewPager + ) + } + } + initViewPager() + } + + private fun initViewPager() { + binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL + binding.viewPager.offscreenPageLimit = 2 + + adapter = NavigationFragmentAdapter(this).apply { + addFragment(DashboardGalleryFragment()) + addFragment(router.getProgramFragmentInstance()) + } + binding.viewPager.adapter = adapter + binding.viewPager.setUserInputEnabled(false) + } +} + +@Composable +private fun Header( + fragmentManager: FragmentManager, + viewPager: ViewPager2 +) { + val viewModel: LearnViewModel = koinViewModel() + val windowSize = rememberWindowSize() + val contentWidth by remember(key1 = windowSize) { + mutableStateOf( + windowSize.windowSizeValue( + expanded = Modifier.widthIn(Dp.Unspecified, 650.dp), + compact = Modifier.fillMaxWidth(), + ) + ) + } + + Column( + modifier = Modifier + .background(MaterialTheme.appColors.background) + .statusBarsInset() + .displayCutoutForLandscape() + .then(contentWidth), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Title( + label = stringResource(id = R.string.dashboard_learn), + onSettingsClick = { + viewModel.onSettingsClick(fragmentManager) + } + ) + + if (viewModel.isProgramTypeWebView) { + LearnDropdownMenu( + modifier = Modifier + .align(Alignment.Start) + .padding(horizontal = 16.dp), + viewPager = viewPager + ) + } + } +} + +@Composable +private fun Title( + modifier: Modifier = Modifier, + label: String, + onSettingsClick: () -> Unit +) { + Box( + modifier = modifier.fillMaxWidth() + ) { + Text( + modifier = Modifier + .align(Alignment.CenterStart) + .padding(start = 16.dp), + text = label, + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.headlineBold + ) + IconButton( + modifier = Modifier + .align(Alignment.CenterEnd) + .padding(end = 12.dp), + onClick = { + onSettingsClick() + } + ) { + Icon( + imageVector = Icons.Default.ManageAccounts, + tint = MaterialTheme.appColors.textAccent, + contentDescription = stringResource(id = CoreR.string.core_accessibility_settings) + ) + } + } +} + +@Composable +private fun LearnDropdownMenu( + modifier: Modifier = Modifier, + viewPager: ViewPager2 +) { + var expanded by remember { mutableStateOf(false) } + var currentValue by remember { mutableStateOf(LearnType.COURSES) } + val iconRotation by animateFloatAsState( + targetValue = if (expanded) 180f else 0f, + label = "" + ) + + LaunchedEffect(currentValue) { + viewPager.setCurrentItem( + when (currentValue) { + LearnType.COURSES -> 0 + LearnType.PROGRAMS -> 1 + }, false + ) + } + + Column( + modifier = modifier + ) { + Row( + modifier = Modifier + .clickable { + expanded = true + }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(id = currentValue.title), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.titleSmall + ) + Icon( + modifier = Modifier.rotate(iconRotation), + imageVector = Icons.Default.ExpandMore, + tint = MaterialTheme.appColors.textDark, + contentDescription = null + ) + } + + MaterialTheme( + colors = MaterialTheme.colors.copy(surface = MaterialTheme.appColors.background), + shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp)) + ) { + DropdownMenu( + modifier = Modifier + .crop(vertical = 8.dp) + .widthIn(min = 182.dp), + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + for (learnType in LearnType.entries) { + val background: Color + val textColor: Color + if (currentValue == learnType) { + background = MaterialTheme.appColors.primary + textColor = MaterialTheme.appColors.primaryButtonText + } else { + background = Color.Transparent + textColor = MaterialTheme.appColors.textDark + } + DropdownMenuItem( + modifier = Modifier + .background(background), + onClick = { + currentValue = learnType + expanded = false + } + ) { + Text( + text = stringResource(id = learnType.title), + style = MaterialTheme.appTypography.titleSmall, + color = textColor + ) + } + } + } + } + } +} + +@Preview +@Composable +private fun HeaderPreview() { + OpenEdXTheme { + Title( + label = stringResource(id = R.string.dashboard_learn), + onSettingsClick = {} + ) + } +} + +@Preview +@Composable +private fun LearnDropdownMenuPreview() { + OpenEdXTheme { + val context = LocalContext.current + LearnDropdownMenu( + viewPager = ViewPager2(context) + ) + } +} diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt new file mode 100644 index 000000000..d2300f652 --- /dev/null +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt @@ -0,0 +1,18 @@ +package org.openedx.learn.presentation + +import androidx.fragment.app.FragmentManager +import org.openedx.core.BaseViewModel +import org.openedx.core.config.Config +import org.openedx.dashboard.presentation.DashboardRouter + +class LearnViewModel( + private val config: Config, + private val dashboardRouter: DashboardRouter +) : BaseViewModel() { + + val isProgramTypeWebView get() = config.getProgramConfig().isViewTypeWebView() + + fun onSettingsClick(fragmentManager: FragmentManager) { + dashboardRouter.navigateToSettings(fragmentManager) + } +} diff --git a/dashboard/src/main/res/drawable/dashboard_ic_book.xml b/dashboard/src/main/res/drawable/dashboard_ic_book.xml new file mode 100644 index 000000000..dd802ee92 --- /dev/null +++ b/dashboard/src/main/res/drawable/dashboard_ic_book.xml @@ -0,0 +1,44 @@ + + + + + + + + + + diff --git a/dashboard/src/main/res/layout/fragment_learn.xml b/dashboard/src/main/res/layout/fragment_learn.xml new file mode 100644 index 000000000..c6556b364 --- /dev/null +++ b/dashboard/src/main/res/layout/fragment_learn.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/dashboard/src/main/res/values/strings.xml b/dashboard/src/main/res/values/strings.xml index 583851adc..4ca0c4fce 100644 --- a/dashboard/src/main/res/values/strings.xml +++ b/dashboard/src/main/res/values/strings.xml @@ -1,7 +1,25 @@ - + Dashboard Courses Welcome back. Let\'s keep learning. You are not enrolled in any courses yet. + Learn + Programs + Course %1$s + Start Course + Resume Course + %1$d Past Due Assignments + View All Courses (%1$d) + View All + %1$s Due in %2$s + All + In Progress + Completed + Expired + All Courses + No Courses + You are not currently enrolled in any courses, would you like to explore the course catalog? + Find a Course + No %1$s Courses diff --git a/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt b/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt index 6fdfdec22..6ca20a255 100644 --- a/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt +++ b/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt @@ -77,7 +77,7 @@ class DashboardViewModelTest { @Test fun `getCourses no internet connection`() = runTest { - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -101,7 +101,7 @@ class DashboardViewModelTest { @Test fun `getCourses unknown error`() = runTest { - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -125,7 +125,7 @@ class DashboardViewModelTest { @Test fun `getCourses from network`() = runTest { - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -149,7 +149,7 @@ class DashboardViewModelTest { @Test fun `getCourses from network with next page`() = runTest { - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -183,7 +183,7 @@ class DashboardViewModelTest { fun `getCourses from cache`() = runTest { every { networkConnection.isOnline() } returns false coEvery { interactor.getEnrolledCoursesFromCache() } returns listOf(mockk()) - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -207,7 +207,7 @@ class DashboardViewModelTest { fun `updateCourses no internet error`() = runTest { every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -235,7 +235,7 @@ class DashboardViewModelTest { fun `updateCourses unknown exception`() = runTest { every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -263,7 +263,7 @@ class DashboardViewModelTest { fun `updateCourses success`() = runTest { every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -296,7 +296,7 @@ class DashboardViewModelTest { "" ) ) - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, @@ -321,7 +321,7 @@ class DashboardViewModelTest { @Test fun `CourseDashboardUpdate notifier test`() = runTest { coEvery { discoveryNotifier.notifier } returns flow { emit(CourseDashboardUpdate()) } - val viewModel = DashboardViewModel( + val viewModel = DashboardListViewModel( config, networkConnection, interactor, diff --git a/default_config/dev/config.yaml b/default_config/dev/config.yaml index e1582bfcf..139652ca6 100644 --- a/default_config/dev/config.yaml +++ b/default_config/dev/config.yaml @@ -28,6 +28,9 @@ PROGRAM: PROGRAM_URL: '' PROGRAM_DETAIL_URL_TEMPLATE: '' +DASHBOARD: + TYPE: 'gallery' + FIREBASE: ENABLED: false ANALYTICS_SOURCE: '' # segment | none @@ -78,4 +81,3 @@ SOCIAL_AUTH_ENABLED: false #Course navigation feature flags COURSE_NESTED_LIST_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false - diff --git a/default_config/prod/config.yaml b/default_config/prod/config.yaml index f7afc7bed..139652ca6 100644 --- a/default_config/prod/config.yaml +++ b/default_config/prod/config.yaml @@ -28,6 +28,9 @@ PROGRAM: PROGRAM_URL: '' PROGRAM_DETAIL_URL_TEMPLATE: '' +DASHBOARD: + TYPE: 'gallery' + FIREBASE: ENABLED: false ANALYTICS_SOURCE: '' # segment | none diff --git a/default_config/stage/config.yaml b/default_config/stage/config.yaml index f7afc7bed..139652ca6 100644 --- a/default_config/stage/config.yaml +++ b/default_config/stage/config.yaml @@ -28,6 +28,9 @@ PROGRAM: PROGRAM_URL: '' PROGRAM_DETAIL_URL_TEMPLATE: '' +DASHBOARD: + TYPE: 'gallery' + FIREBASE: ENABLED: false ANALYTICS_SOURCE: '' # segment | none diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt index ee3e04a3b..3b74dbc42 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt @@ -68,7 +68,10 @@ import org.openedx.discovery.presentation.catalog.WebViewLink import org.openedx.core.R as coreR import org.openedx.discovery.presentation.catalog.WebViewLink.Authority as linkAuthority -class ProgramFragment(private val myPrograms: Boolean = false) : Fragment() { +class ProgramFragment( + private val myPrograms: Boolean = false, + private val isNestedFragment: Boolean = false +) : Fragment() { private val viewModel by viewModel() @@ -127,6 +130,7 @@ class ProgramFragment(private val myPrograms: Boolean = false) : Fragment() { cookieManager = viewModel.cookieManager, canShowBackBtn = arguments?.getString(ARG_PATH_ID, "") ?.isNotEmpty() == true, + isNestedFragment = isNestedFragment, uriScheme = viewModel.uriScheme, hasInternetConnection = hasInternetConnection, checkInternetConnection = { @@ -224,6 +228,7 @@ private fun ProgramInfoScreen( cookieManager: AppCookieManager, uriScheme: String, canShowBackBtn: Boolean, + isNestedFragment: Boolean, hasInternetConnection: Boolean, checkInternetConnection: () -> Unit, onWebPageLoaded: () -> Unit, @@ -250,7 +255,7 @@ private fun ProgramInfoScreen( .fillMaxSize() .semantics { testTagsAsResourceId = true }, backgroundColor = MaterialTheme.appColors.background - ) { + ) { paddingValues -> val modifierScreenWidth by remember(key1 = windowSize) { mutableStateOf( windowSize.windowSizeValue( @@ -264,21 +269,29 @@ private fun ProgramInfoScreen( ) } + val statusBarPadding = if (isNestedFragment) { + Modifier + } else { + Modifier.statusBarsInset() + } + Column( modifier = Modifier .fillMaxSize() - .padding(it) - .statusBarsInset() + .padding(paddingValues) + .then(statusBarPadding) .displayCutoutForLandscape(), horizontalAlignment = Alignment.CenterHorizontally, ) { - Toolbar( - label = stringResource(id = R.string.discovery_programs), - canShowBackBtn = canShowBackBtn, - canShowSettingsIcon = !canShowBackBtn, - onBackClick = onBackClick, - onSettingsClick = onSettingsClick - ) + if (!isNestedFragment) { + Toolbar( + label = stringResource(id = R.string.discovery_programs), + canShowBackBtn = canShowBackBtn, + canShowSettingsIcon = !canShowBackBtn, + onBackClick = onBackClick, + onSettingsClick = onSettingsClick + ) + } Surface { Box( @@ -349,6 +362,7 @@ fun MyProgramsPreview() { cookieManager = koinViewModel().cookieManager, uriScheme = "", canShowBackBtn = false, + isNestedFragment = false, hasInternetConnection = false, checkInternetConnection = {}, onBackClick = {}, diff --git a/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt b/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt index 46552edc9..456eb79c2 100644 --- a/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt +++ b/discussion/src/main/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModel.kt @@ -11,11 +11,10 @@ import org.openedx.core.BaseViewModel import org.openedx.core.R import org.openedx.core.UIMessage import org.openedx.core.extension.isInternetError -import org.openedx.core.presentation.course.CourseContainerTab import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier -import org.openedx.core.system.notifier.CourseRefresh +import org.openedx.core.system.notifier.RefreshDiscussions import org.openedx.discussion.domain.interactor.DiscussionInteractor import org.openedx.discussion.presentation.DiscussionAnalytics import org.openedx.discussion.presentation.DiscussionRouter @@ -81,11 +80,7 @@ class DiscussionTopicsViewModel( viewModelScope.launch { courseNotifier.notifier.collect { event -> when (event) { - is CourseRefresh -> { - if (event.courseContainerTab == CourseContainerTab.DISCUSSIONS) { - getCourseTopic() - } - } + is RefreshDiscussions -> getCourseTopic() } } } diff --git a/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt index a9094c67d..8d49fb8ec 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/calendar/CalendarAccessDialogFragment.kt @@ -128,7 +128,7 @@ private fun CalendarAccessDialog( TextIcon( text = stringResource(id = R.string.profile_grant_access_calendar), icon = Icons.AutoMirrored.Filled.OpenInNew, - color = MaterialTheme.appColors.buttonText, + color = MaterialTheme.appColors.primaryButtonText, textStyle = MaterialTheme.appTypography.labelLarge, iconModifier = Modifier.padding(start = 4.dp) ) @@ -138,8 +138,8 @@ private fun CalendarAccessDialog( modifier = Modifier.fillMaxWidth(), text = stringResource(id = CoreR.string.core_cancel), backgroundColor = MaterialTheme.appColors.background, - borderColor = MaterialTheme.appColors.buttonBackground, - textColor = MaterialTheme.appColors.buttonBackground, + borderColor = MaterialTheme.appColors.primaryButtonBackground, + textColor = MaterialTheme.appColors.primaryButtonBackground, onClick = { onCancelClick() } diff --git a/profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt index bfd453f5c..8e55b885b 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/calendar/NewCalendarDialogFragment.kt @@ -172,8 +172,8 @@ private fun NewCalendarDialog( modifier = Modifier.fillMaxWidth(), text = stringResource(id = CoreR.string.core_cancel), backgroundColor = MaterialTheme.appColors.background, - borderColor = MaterialTheme.appColors.buttonBackground, - textColor = MaterialTheme.appColors.buttonBackground, + borderColor = MaterialTheme.appColors.primaryButtonBackground, + textColor = MaterialTheme.appColors.primaryButtonBackground, onClick = { onCancelClick() } From 3df3c05be0755ed9312b7bde7386d131643986f6 Mon Sep 17 00:00:00 2001 From: Omer Habib <30689349+omerhabib26@users.noreply.github.com> Date: Fri, 31 May 2024 16:24:24 +0500 Subject: [PATCH 07/38] fix: update config parsing structure (#319) fix: update config parsing structure - Update dictionary for ProgramConfig - Update UI related feature flags under a single Key - fix image load in course fix: LEARNER-9891 * fix: Updated minor fix --- .../java/org/openedx/core/config/Config.kt | 45 ++++++++----------- .../org/openedx/core/config/ProgramConfig.kt | 2 +- .../java/org/openedx/core/config/UIConfig.kt | 10 +++++ .../dates/CourseDatesViewModel.kt | 2 +- .../outline/CourseOutlineViewModel.kt | 4 +- .../course/presentation/ui/CourseUI.kt | 26 +++++------ .../container/CourseUnitContainerViewModel.kt | 4 +- .../unit/html/HtmlUnitViewModel.kt | 2 +- .../videos/CourseVideoViewModel.kt | 2 +- .../outline/CourseOutlineViewModelTest.kt | 12 ++--- .../videos/CourseVideoViewModelTest.kt | 14 +++--- .../presentation/DashboardListFragment.kt | 2 +- default_config/dev/config.yaml | 10 +++-- default_config/prod/config.yaml | 9 ++-- default_config/stage/config.yaml | 9 ++-- .../discovery/presentation/ui/DiscoveryUI.kt | 4 +- 16 files changed, 81 insertions(+), 76 deletions(-) create mode 100644 core/src/main/java/org/openedx/core/config/UIConfig.kt diff --git a/core/src/main/java/org/openedx/core/config/Config.kt b/core/src/main/java/org/openedx/core/config/Config.kt index 4e39a0861..57f91ef88 100644 --- a/core/src/main/java/org/openedx/core/config/Config.kt +++ b/core/src/main/java/org/openedx/core/config/Config.kt @@ -10,17 +10,13 @@ import java.io.InputStreamReader class Config(context: Context) { - private var configProperties: JsonObject - - init { - configProperties = try { - val inputStream = context.assets.open("config/config.json") - val parser = JsonParser() - val config = parser.parse(InputStreamReader(inputStream)) - config.asJsonObject - } catch (e: Exception) { - JsonObject() - } + private var configProperties: JsonObject = try { + val inputStream = context.assets.open("config/config.json") + val parser = JsonParser() + val config = parser.parse(InputStreamReader(inputStream)) + config.asJsonObject + } catch (e: Exception) { + JsonObject() } fun getAppId(): String { @@ -28,31 +24,31 @@ class Config(context: Context) { } fun getApiHostURL(): String { - return getString(API_HOST_URL, "") + return getString(API_HOST_URL) } fun getUriScheme(): String { - return getString(URI_SCHEME, "") + return getString(URI_SCHEME) } fun getOAuthClientId(): String { - return getString(OAUTH_CLIENT_ID, "") + return getString(OAUTH_CLIENT_ID) } fun getAccessTokenType(): String { - return getString(TOKEN_TYPE, "") + return getString(TOKEN_TYPE) } fun getFaqUrl(): String { - return getString(FAQ_URL, "") + return getString(FAQ_URL) } fun getFeedbackEmailAddress(): String { - return getString(FEEDBACK_EMAIL_ADDRESS, "") + return getString(FEEDBACK_EMAIL_ADDRESS) } fun getPlatformName(): String { - return getString(PLATFORM_NAME, "") + return getString(PLATFORM_NAME) } fun getAgreement(locale: String): AgreementUrls { @@ -111,15 +107,11 @@ class Config(context: Context) { return getBoolean(PRE_LOGIN_EXPERIENCE_ENABLED, true) } - fun isCourseNestedListEnabled(): Boolean { - return getBoolean(COURSE_NESTED_LIST_ENABLED, false) - } - - fun isCourseUnitProgressEnabled(): Boolean { - return getBoolean(COURSE_UNIT_PROGRESS_ENABLED, false) + fun getCourseUIConfig(): UIConfig { + return getObjectOrNewInstance(UI_COMPONENTS, UIConfig::class.java) } - private fun getString(key: String, defaultValue: String): String { + private fun getString(key: String, defaultValue: String = ""): String { val element = getObject(key) return if (element != null) { element.asString @@ -175,8 +167,7 @@ class Config(context: Context) { private const val PROGRAM = "PROGRAM" private const val DASHBOARD = "DASHBOARD" private const val BRANCH = "BRANCH" - private const val COURSE_NESTED_LIST_ENABLED = "COURSE_NESTED_LIST_ENABLED" - private const val COURSE_UNIT_PROGRESS_ENABLED = "COURSE_UNIT_PROGRESS_ENABLED" + private const val UI_COMPONENTS = "UI_COMPONENTS" private const val PLATFORM_NAME = "PLATFORM_NAME" } diff --git a/core/src/main/java/org/openedx/core/config/ProgramConfig.kt b/core/src/main/java/org/openedx/core/config/ProgramConfig.kt index c553f8997..ce34365ec 100644 --- a/core/src/main/java/org/openedx/core/config/ProgramConfig.kt +++ b/core/src/main/java/org/openedx/core/config/ProgramConfig.kt @@ -16,6 +16,6 @@ data class ProgramConfig( data class ProgramWebViewConfig( @SerializedName("BASE_URL") val programUrl: String = "", - @SerializedName("PROGRAM_DETAIL_URL_TEMPLATE") + @SerializedName("PROGRAM_DETAIL_TEMPLATE") val programDetailUrlTemplate: String = "", ) diff --git a/core/src/main/java/org/openedx/core/config/UIConfig.kt b/core/src/main/java/org/openedx/core/config/UIConfig.kt new file mode 100644 index 000000000..1f8443d27 --- /dev/null +++ b/core/src/main/java/org/openedx/core/config/UIConfig.kt @@ -0,0 +1,10 @@ +package org.openedx.core.config + +import com.google.gson.annotations.SerializedName + +data class UIConfig( + @SerializedName("COURSE_NESTED_LIST_ENABLED") + val isCourseNestedListEnabled: Boolean = false, + @SerializedName("COURSE_UNIT_PROGRESS_ENABLED") + val isCourseUnitProgressEnabled: Boolean = 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 2591a8f3e..a6a78cb72 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 @@ -77,7 +77,7 @@ class CourseDatesViewModel( private var courseBannerType: CourseBannerType = CourseBannerType.BLANK private var courseStructure: CourseStructure? = null - val isCourseExpandableSectionsEnabled get() = config.isCourseNestedListEnabled() + val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled init { viewModelScope.launch { 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 f533410b8..11ec94d95 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 @@ -64,7 +64,7 @@ class CourseOutlineViewModel( workerController, coreAnalytics ) { - val isCourseNestedListEnabled get() = config.isCourseNestedListEnabled() + val isCourseNestedListEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled private val _uiState = MutableStateFlow(CourseOutlineUIState.Loading) val uiState: StateFlow @@ -81,7 +81,7 @@ class CourseOutlineViewModel( private var resumeSectionBlock: Block? = null private var resumeVerticalBlock: Block? = null - private val isCourseExpandableSectionsEnabled get() = config.isCourseNestedListEnabled() + private val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled private val courseSubSections = mutableMapOf>() private val subSectionsDownloadsCount = mutableMapOf() 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 10fa4ef84..6a89c1dc2 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 @@ -103,7 +103,7 @@ fun CourseSectionCard( block: Block, downloadedState: DownloadedState?, onItemClick: (Block) -> Unit, - onDownloadClick: (Block) -> Unit + onDownloadClick: (Block) -> Unit, ) { val iconModifier = Modifier.size(24.dp) @@ -204,7 +204,7 @@ fun OfflineQueueCard( downloadModel: DownloadModel, progressValue: Long, progressSize: Long, - onDownloadClick: (DownloadModel) -> Unit + onDownloadClick: (DownloadModel) -> Unit, ) { val iconModifier = Modifier.size(24.dp) @@ -272,7 +272,7 @@ fun OfflineQueueCard( @Composable fun CardArrow( - degrees: Float + degrees: Float, ) { Icon( imageVector = Icons.Filled.ChevronRight, @@ -304,7 +304,7 @@ fun NavigationUnitsButtons( hasNextBlock: Boolean, isVerticalNavigation: Boolean, onPrevClick: () -> Unit, - onNextClick: () -> Unit + onNextClick: () -> Unit, ) { val nextButtonIcon = if (hasNextBlock) { painterResource(id = coreR.drawable.core_ic_down) @@ -403,7 +403,7 @@ fun HorizontalPageIndicator( completedAndSelectedColor: Color = Color.Green, completedColor: Color = Color.Green, selectedColor: Color = Color.White, - defaultColor: Color = Color.Gray + defaultColor: Color = Color.Gray, ) { Row( horizontalArrangement = Arrangement.spacedBy(1.dp), @@ -468,7 +468,7 @@ fun Indicator( defaultColor: Color, defaultRadius: Dp, selectedSize: Dp, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { val size by animateDpAsState( targetValue = if (isSelected) selectedSize else defaultRadius, @@ -497,7 +497,7 @@ fun VideoSubtitles( showSubtitleLanguage: Boolean, currentIndex: Int, onTranscriptClick: (Caption) -> Unit, - onSettingsClick: () -> Unit + onSettingsClick: () -> Unit, ) { timedTextObject?.let { val autoScrollDelay = 3000L @@ -577,7 +577,7 @@ fun CourseExpandableChapterCard( modifier: Modifier, block: Block, onItemClick: (Block) -> Unit, - arrowDegrees: Float = 0f + arrowDegrees: Float = 0f, ) { Column(modifier = Modifier .clickable { onItemClick(block) } @@ -627,7 +627,7 @@ fun CourseSubSectionItem( downloadedState: DownloadedState?, downloadsCount: Int, onClick: (Block) -> Unit, - onDownloadClick: (Block) -> Unit + onDownloadClick: (Block) -> Unit, ) { val icon = if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource( @@ -729,7 +729,7 @@ fun CourseSubSectionItem( @Composable fun CourseUnitToolbar( title: String, - onBackClick: () -> Unit + onBackClick: () -> Unit, ) { OpenEdXTheme { Box( @@ -759,7 +759,7 @@ fun SubSectionUnitsTitle( unitName: String, unitsCount: Int, unitsListShowed: Boolean, - onUnitsClick: () -> Unit + onUnitsClick: () -> Unit, ) { val textStyle = MaterialTheme.appTypography.titleMedium val hasUnits = unitsCount > 0 @@ -805,7 +805,7 @@ fun SubSectionUnitsTitle( fun SubSectionUnitsList( unitBlocks: List, selectedUnitIndex: Int = 0, - onUnitClick: (index: Int, unit: Block) -> Unit + onUnitClick: (index: Int, unit: Block) -> Unit, ) { Card( modifier = Modifier @@ -1050,7 +1050,7 @@ fun CourseMessage( icon: Painter, message: String, action: String? = null, - onActionClick: () -> Unit = {} + onActionClick: () -> Unit = {}, ) { Column { Row( diff --git a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt index f479f08c0..61fc896bf 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt @@ -37,9 +37,9 @@ class CourseUnitContainerViewModel( private val blocks = ArrayList() - val isCourseExpandableSectionsEnabled get() = config.isCourseNestedListEnabled() + val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled - val isCourseUnitProgressEnabled get() = config.isCourseUnitProgressEnabled() + val isCourseUnitProgressEnabled get() = config.getCourseUIConfig().isCourseUnitProgressEnabled private var currentIndex = 0 private var currentVerticalIndex = 0 diff --git a/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitViewModel.kt b/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitViewModel.kt index c65fcb33e..9d52c979b 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/html/HtmlUnitViewModel.kt @@ -24,7 +24,7 @@ class HtmlUnitViewModel( val injectJSList = _injectJSList.asStateFlow() val isOnline get() = networkConnection.isOnline() - val isCourseUnitProgressEnabled get() = config.isCourseUnitProgressEnabled() + val isCourseUnitProgressEnabled get() = config.getCourseUIConfig().isCourseUnitProgressEnabled val apiHostURL get() = config.getApiHostURL() val cookieManager get() = edxCookieManager diff --git a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt index b8f2e8fb1..2cf3d8797 100644 --- a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt @@ -53,7 +53,7 @@ class CourseVideoViewModel( coreAnalytics ) { - val isCourseNestedListEnabled get() = config.isCourseNestedListEnabled() + val isCourseNestedListEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled private val _uiState = MutableStateFlow(CourseVideosUIState.Loading) val uiState: StateFlow 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 45abb10ee..941fbfdac 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 @@ -303,7 +303,7 @@ class CourseOutlineViewModelTest { ) } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -351,7 +351,7 @@ class CourseOutlineViewModelTest { ) } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -398,7 +398,7 @@ class CourseOutlineViewModelTest { ) } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -482,7 +482,7 @@ class CourseOutlineViewModelTest { coEvery { workerController.saveModels(any()) } returns Unit coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -525,7 +525,7 @@ class CourseOutlineViewModelTest { every { networkConnection.isOnline() } returns true coEvery { workerController.saveModels(any()) } returns Unit coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false every { coreAnalytics.logEvent(any(), any()) } returns Unit val viewModel = CourseOutlineViewModel( @@ -562,7 +562,7 @@ class CourseOutlineViewModelTest { every { networkConnection.isOnline() } returns false coEvery { workerController.saveModels(any()) } returns Unit coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false val viewModel = CourseOutlineViewModel( "", diff --git a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt index 7962011db..a15de0583 100644 --- a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt @@ -183,7 +183,7 @@ class CourseVideoViewModelTest { @Test fun `getVideos empty list`() = runTest { - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure.copy(blockData = emptyList()) every { downloadDao.readAllData() } returns flow { emit(emptyList()) } @@ -215,7 +215,7 @@ class CourseVideoViewModelTest { @Test fun `getVideos success`() = runTest { - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure every { downloadDao.readAllData() } returns flow { emit(emptyList()) } every { preferencesManager.videoSettings } returns VideoSettings.default @@ -248,7 +248,7 @@ class CourseVideoViewModelTest { @Test fun `updateVideos success`() = runTest { - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { courseNotifier.notifier } returns flow { emit(CourseStructureUpdated("")) @@ -291,7 +291,7 @@ class CourseVideoViewModelTest { @Test fun `setIsUpdating success`() = runTest { - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } @@ -300,7 +300,7 @@ class CourseVideoViewModelTest { @Test fun `saveDownloadModels test`() = runTest(UnconfinedTestDispatcher()) { - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default val viewModel = CourseVideoViewModel( "", @@ -337,7 +337,7 @@ class CourseVideoViewModelTest { @Test fun `saveDownloadModels only wifi download, with connection`() = runTest(UnconfinedTestDispatcher()) { - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default val viewModel = CourseVideoViewModel( "", @@ -378,7 +378,7 @@ class CourseVideoViewModelTest { @Test fun `saveDownloadModels only wifi download, without connection`() = runTest(UnconfinedTestDispatcher()) { - every { config.isCourseNestedListEnabled() } returns false + every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default val viewModel = CourseVideoViewModel( "", diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index 597958e51..127164cc2 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -391,7 +391,7 @@ private fun CourseItem( ) ) } - val imageUrl = apiHostUrl.dropLast(1) + enrolledCourse.course.courseImage + val imageUrl = apiHostUrl + enrolledCourse.course.courseImage val context = LocalContext.current Surface( modifier = Modifier diff --git a/default_config/dev/config.yaml b/default_config/dev/config.yaml index 139652ca6..8c08df7f6 100644 --- a/default_config/dev/config.yaml +++ b/default_config/dev/config.yaml @@ -25,8 +25,8 @@ DISCOVERY: PROGRAM: TYPE: 'native' WEBVIEW: - PROGRAM_URL: '' - PROGRAM_DETAIL_URL_TEMPLATE: '' + BASE_URL: '' + PROGRAM_DETAIL_TEMPLATE: '' DASHBOARD: TYPE: 'gallery' @@ -79,5 +79,7 @@ WHATS_NEW_ENABLED: false #feature flag enable Social Login buttons SOCIAL_AUTH_ENABLED: false #Course navigation feature flags -COURSE_NESTED_LIST_ENABLED: false -COURSE_UNIT_PROGRESS_ENABLED: false +UI_COMPONENTS: + COURSE_NESTED_LIST_ENABLED: false + COURSE_UNIT_PROGRESS_ENABLED: false + diff --git a/default_config/prod/config.yaml b/default_config/prod/config.yaml index 139652ca6..8b1dc8f07 100644 --- a/default_config/prod/config.yaml +++ b/default_config/prod/config.yaml @@ -25,8 +25,8 @@ DISCOVERY: PROGRAM: TYPE: 'native' WEBVIEW: - PROGRAM_URL: '' - PROGRAM_DETAIL_URL_TEMPLATE: '' + BASE_URL: '' + PROGRAM_DETAIL_TEMPLATE: '' DASHBOARD: TYPE: 'gallery' @@ -79,5 +79,6 @@ WHATS_NEW_ENABLED: false #feature flag enable Social Login buttons SOCIAL_AUTH_ENABLED: false #Course navigation feature flags -COURSE_NESTED_LIST_ENABLED: false -COURSE_UNIT_PROGRESS_ENABLED: false +UI_COMPONENTS: + COURSE_NESTED_LIST_ENABLED: false + COURSE_UNIT_PROGRESS_ENABLED: false diff --git a/default_config/stage/config.yaml b/default_config/stage/config.yaml index 139652ca6..8b1dc8f07 100644 --- a/default_config/stage/config.yaml +++ b/default_config/stage/config.yaml @@ -25,8 +25,8 @@ DISCOVERY: PROGRAM: TYPE: 'native' WEBVIEW: - PROGRAM_URL: '' - PROGRAM_DETAIL_URL_TEMPLATE: '' + BASE_URL: '' + PROGRAM_DETAIL_TEMPLATE: '' DASHBOARD: TYPE: 'gallery' @@ -79,5 +79,6 @@ WHATS_NEW_ENABLED: false #feature flag enable Social Login buttons SOCIAL_AUTH_ENABLED: false #Course navigation feature flags -COURSE_NESTED_LIST_ENABLED: false -COURSE_UNIT_PROGRESS_ENABLED: false +UI_COMPONENTS: + COURSE_NESTED_LIST_ENABLED: false + COURSE_UNIT_PROGRESS_ENABLED: false diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/ui/DiscoveryUI.kt b/discovery/src/main/java/org/openedx/discovery/presentation/ui/DiscoveryUI.kt index e1b6645ea..30c2a63d2 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/ui/DiscoveryUI.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/ui/DiscoveryUI.kt @@ -70,7 +70,7 @@ fun ImageHeader( val imageUrl = if (courseImage?.isLinkValid() == true) { courseImage } else { - apiHostUrl.dropLast(1) + courseImage + apiHostUrl + courseImage } Box(modifier = modifier, contentAlignment = Alignment.Center) { AsyncImage( @@ -108,7 +108,7 @@ fun DiscoveryCourseItem( ) } - val imageUrl = apiHostUrl.dropLast(1) + course.media.courseImage?.uri + val imageUrl = apiHostUrl + course.media.courseImage?.uri Surface( modifier = Modifier .testTag("btn_course_card") From 3e9556036ec520965ce6344fe096684e9ab4bea8 Mon Sep 17 00:00:00 2001 From: Omer Habib <30689349+omerhabib26@users.noreply.github.com> Date: Fri, 31 May 2024 16:24:56 +0500 Subject: [PATCH 08/38] feat: delete old videos Directory (#326) feat: delete old videos Directory - Delete all the videos and folders of old app fix: LEARNER-9950 --- .../main/java/org/openedx/app/AppViewModel.kt | 11 +++++ .../app/data/storage/PreferencesManager.kt | 7 +++ .../java/org/openedx/app/di/ScreenModule.kt | 2 +- .../test/java/org/openedx/AppViewModelTest.kt | 35 +++++++++++++-- .../core/data/storage/CorePreferences.kt | 1 + .../java/org/openedx/core/utils/FileUtil.kt | 43 ++++++++++++++++++- .../presentation/DashboardListFragment.kt | 2 +- .../presentation/DashboardListViewModel.kt | 2 +- 8 files changed, 96 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/openedx/app/AppViewModel.kt b/app/src/main/java/org/openedx/app/AppViewModel.kt index 1febbd15a..c18e48026 100644 --- a/app/src/main/java/org/openedx/app/AppViewModel.kt +++ b/app/src/main/java/org/openedx/app/AppViewModel.kt @@ -13,6 +13,7 @@ import org.openedx.core.BaseViewModel import org.openedx.core.SingleEventLiveData import org.openedx.core.config.Config import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.utils.FileUtil class AppViewModel( private val config: Config, @@ -21,6 +22,7 @@ class AppViewModel( private val preferencesManager: CorePreferences, private val dispatcher: CoroutineDispatcher, private val analytics: AppAnalytics, + private val fileUtil: FileUtil, ) : BaseViewModel() { private val _logoutUser = SingleEventLiveData() @@ -32,10 +34,14 @@ class AppViewModel( private var logoutHandledAt: Long = 0 val isBranchEnabled get() = config.getBranchConfig().enabled + private val canResetAppDirectory get() = preferencesManager.canResetAppDirectory override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) setUserId() + if (canResetAppDirectory) { + resetAppDirectory() + } viewModelScope.launch { notifier.notifier.collect { event -> if (event is LogoutEvent && System.currentTimeMillis() - logoutHandledAt > 5000) { @@ -60,6 +66,11 @@ class AppViewModel( ) } + private fun resetAppDirectory() { + fileUtil.deleteOldAppDirectory() + preferencesManager.canResetAppDirectory = false + } + private fun setUserId() { preferencesManager.user?.let { analytics.setUserIdForSession(it.id) diff --git a/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt b/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt index 603876d54..e0b65af14 100644 --- a/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt +++ b/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt @@ -152,6 +152,12 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences } get() = getBoolean(APP_WAS_POSITIVE_RATED) + override var canResetAppDirectory: Boolean + set(value) { + saveBoolean(RESET_APP_DIRECTORY, value) + } + get() = getBoolean(RESET_APP_DIRECTORY, true) + override fun setCalendarSyncEventsDialogShown(courseName: String) { saveBoolean(courseName.replaceSpace("_"), true) } @@ -172,5 +178,6 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences private const val VIDEO_SETTINGS_STREAMING_QUALITY = "video_settings_streaming_quality" private const val VIDEO_SETTINGS_DOWNLOAD_QUALITY = "video_settings_download_quality" private const val APP_CONFIG = "app_config" + private const val RESET_APP_DIRECTORY = "reset_app_directory" } } diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index cd3615e26..393b16248 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -67,7 +67,7 @@ import org.openedx.whatsnew.presentation.whatsnew.WhatsNewViewModel val screenModule = module { - viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get()) } + viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get(), get()) } viewModel { MainViewModel(get(), get(), get()) } factory { AuthRepository(get(), get(), get()) } diff --git a/app/src/test/java/org/openedx/AppViewModelTest.kt b/app/src/test/java/org/openedx/AppViewModelTest.kt index 40b3e813d..c81c9c2e5 100644 --- a/app/src/test/java/org/openedx/AppViewModelTest.kt +++ b/app/src/test/java/org/openedx/AppViewModelTest.kt @@ -28,6 +28,7 @@ import org.openedx.app.system.notifier.AppNotifier import org.openedx.app.system.notifier.LogoutEvent import org.openedx.core.config.Config import org.openedx.core.data.model.User +import org.openedx.core.utils.FileUtil @ExperimentalCoroutinesApi class AppViewModelTest { @@ -42,6 +43,7 @@ class AppViewModelTest { private val room = mockk() private val preferencesManager = mockk() private val analytics = mockk() + private val fileUtil = mockk() private val user = User(0, "", "", "") @@ -60,8 +62,17 @@ class AppViewModelTest { every { analytics.setUserIdForSession(any()) } returns Unit every { preferencesManager.user } returns user every { notifier.notifier } returns flow { } + every { preferencesManager.canResetAppDirectory } returns false val viewModel = - AppViewModel(config, notifier, room, preferencesManager, dispatcher, analytics) + AppViewModel( + config, + notifier, + room, + preferencesManager, + dispatcher, + analytics, + fileUtil + ) val mockLifeCycleOwner: LifecycleOwner = mockk() val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner) @@ -82,8 +93,17 @@ class AppViewModelTest { every { preferencesManager.user } returns user every { room.clearAllTables() } returns Unit every { analytics.logoutEvent(true) } returns Unit + every { preferencesManager.canResetAppDirectory } returns false val viewModel = - AppViewModel(config, notifier, room, preferencesManager, dispatcher, analytics) + AppViewModel( + config, + notifier, + room, + preferencesManager, + dispatcher, + analytics, + fileUtil + ) val mockLifeCycleOwner: LifecycleOwner = mockk() val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner) @@ -106,8 +126,17 @@ class AppViewModelTest { every { preferencesManager.user } returns user every { room.clearAllTables() } returns Unit every { analytics.logoutEvent(true) } returns Unit + every { preferencesManager.canResetAppDirectory } returns false val viewModel = - AppViewModel(config, notifier, room, preferencesManager, dispatcher, analytics) + AppViewModel( + config, + notifier, + room, + preferencesManager, + dispatcher, + analytics, + fileUtil + ) val mockLifeCycleOwner: LifecycleOwner = mockk() val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner) diff --git a/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt b/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt index 48999ab4e..f9cacbd04 100644 --- a/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt +++ b/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt @@ -11,6 +11,7 @@ interface CorePreferences { var user: User? var videoSettings: VideoSettings var appConfig: AppConfig + var canResetAppDirectory: Boolean fun clear() } diff --git a/core/src/main/java/org/openedx/core/utils/FileUtil.kt b/core/src/main/java/org/openedx/core/utils/FileUtil.kt index 2f5c2b2e5..a59317193 100644 --- a/core/src/main/java/org/openedx/core/utils/FileUtil.kt +++ b/core/src/main/java/org/openedx/core/utils/FileUtil.kt @@ -4,6 +4,7 @@ import android.content.Context import com.google.gson.Gson import com.google.gson.GsonBuilder import java.io.File +import java.util.Collections class FileUtil(val context: Context) { @@ -15,7 +16,10 @@ class FileUtil(val context: Context) { return file } - inline fun saveObjectToFile(obj: T, fileName: String = "${T::class.java.simpleName}.json") { + inline fun saveObjectToFile( + obj: T, + fileName: String = "${T::class.java.simpleName}.json", + ) { val gson: Gson = GsonBuilder().setPrettyPrinting().create() val jsonString = gson.toJson(obj) File(getExternalAppDir().path + fileName).writeText(jsonString) @@ -31,6 +35,43 @@ class FileUtil(val context: Context) { null } } + + /** + * Deletes all the files and directories in the app's external storage directory. + */ + fun deleteOldAppDirectory() { + val externalFilesDir = context.getExternalFilesDir(null) + val externalAppDir = File(externalFilesDir?.parentFile, Directories.VIDEOS.name) + if (externalAppDir.isDirectory) { + deleteRecursive(externalAppDir, Collections.emptyList()) + } + } + + /** + * Deletes a file or directory and all its content recursively. + * + * @param fileOrDirectory The file or directory that needs to be deleted. + * @param exceptions Names of the files or directories that need to be skipped while deletion. + */ + private fun deleteRecursive( + fileOrDirectory: File, + exceptions: List, + ) { + if (exceptions.contains(fileOrDirectory.name)) return + + if (fileOrDirectory.isDirectory) { + val filesList = fileOrDirectory.listFiles() + if (filesList != null) { + for (child in filesList) { + deleteRecursive(child, exceptions) + } + } + } + + // Don't break the recursion upon encountering an error + // noinspection ResultOfMethodCallIgnored + fileOrDirectory.delete() + } } enum class Directories { diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index 127164cc2..0a7f59c93 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -381,7 +381,7 @@ private fun CourseItem( apiHostUrl: String, enrolledCourse: EnrolledCourse, windowSize: WindowSize, - onClick: (EnrolledCourse) -> Unit + onClick: (EnrolledCourse) -> Unit, ) { val imageWidth by remember(key1 = windowSize) { mutableStateOf( diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt index 812e52f2e..82814561a 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt @@ -27,7 +27,7 @@ class DashboardListViewModel( private val resourceManager: ResourceManager, private val discoveryNotifier: DiscoveryNotifier, private val analytics: DashboardAnalytics, - private val appUpgradeNotifier: AppUpgradeNotifier + private val appUpgradeNotifier: AppUpgradeNotifier, ) : BaseViewModel() { private val coursesList = mutableListOf() From 22ee1768769d9eb335cc249f385126c1d2a05fac Mon Sep 17 00:00:00 2001 From: Omer Habib <30689349+omerhabib26@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:11:48 +0500 Subject: [PATCH 09/38] fix: Accessibility issue on courseDashboard (#327) - added content description for views fix: LEARNER-10021 --- .../container/CollapsingLayout.kt | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt b/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt index 64ba858d8..08f6cf96a 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Density @@ -64,6 +65,7 @@ import androidx.compose.ui.unit.dp import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import org.openedx.core.R import org.openedx.core.ui.RoundTabsBar import org.openedx.core.ui.displayCutoutForLandscape import org.openedx.core.ui.rememberWindowSize @@ -104,7 +106,8 @@ internal fun CollapsingLayout( val factor = if (rawFactor.isNaN() || rawFactor < 0) 0f else rawFactor val blurImagePadding = 40.dp val blurImagePaddingPx = with(localDensity) { blurImagePadding.toPx() } - val toolbarOffset = (offset.value + backgroundImageHeight.floatValue - blurImagePaddingPx).roundToInt() + val toolbarOffset = + (offset.value + backgroundImageHeight.floatValue - blurImagePaddingPx).roundToInt() val imageStartY = (backgroundImageHeight.floatValue - blurImagePaddingPx) * 0.5f val imageOffsetY = -(offset.value + imageStartY) val toolbarBackgroundOffset = if (toolbarOffset >= 0) { @@ -393,7 +396,12 @@ private fun CollapsingLayoutTablet( Box( modifier = Modifier - .offset { IntOffset(x = 0, y = (backgroundImageHeight.value + expandedTopHeight.value).roundToInt()) } + .offset { + IntOffset( + x = 0, + y = (backgroundImageHeight.value + expandedTopHeight.value).roundToInt() + ) + } .onSizeChanged { size -> navigationHeight.value = size.height.toFloat() }, @@ -516,7 +524,7 @@ private fun CollapsingLayoutMobile( }, imageVector = Icons.AutoMirrored.Filled.ArrowBack, tint = MaterialTheme.appColors.textPrimary, - contentDescription = null + contentDescription = stringResource(id = R.string.core_accessibility_btn_back) ) Spacer(modifier = Modifier.width(8.dp)) Box( @@ -679,7 +687,7 @@ private fun CollapsingLayoutMobile( }, imageVector = Icons.AutoMirrored.Filled.ArrowBack, tint = MaterialTheme.appColors.textPrimary, - contentDescription = null + contentDescription = stringResource(id = R.string.core_accessibility_btn_back) ) Spacer(modifier = Modifier.width(8.dp)) Box( @@ -721,8 +729,14 @@ private fun CollapsingLayoutMobile( @OptIn(ExperimentalFoundationApi::class) @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, device = "spec:parent=pixel_5,orientation=landscape") -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, device = "spec:parent=pixel_5,orientation=landscape") +@Preview( + uiMode = Configuration.UI_MODE_NIGHT_NO, + device = "spec:parent=pixel_5,orientation=landscape" +) +@Preview( + uiMode = Configuration.UI_MODE_NIGHT_YES, + device = "spec:parent=pixel_5,orientation=landscape" +) @Preview(device = Devices.NEXUS_9, uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(device = Devices.NEXUS_9, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -758,7 +772,7 @@ private fun CollapsingLayoutPreview() { suspend fun PointerInputScope.routePointerChangesTo( onDown: (PointerInputChange) -> Unit = {}, - onUp: (PointerInputChange) -> Unit = {} + onUp: (PointerInputChange) -> Unit = {}, ) { awaitEachGesture { do { @@ -776,7 +790,7 @@ suspend fun PointerInputScope.routePointerChangesTo( @Immutable data class PixelAlignment( val offsetX: Float, - val offsetY: Float + val offsetY: Float, ) : Alignment { override fun align(size: IntSize, space: IntSize, layoutDirection: LayoutDirection): IntOffset { From 1bc1d4c97c496bce20780f5e2d3e2aaf0ab8fbd2 Mon Sep 17 00:00:00 2001 From: PavloNetrebchuk <141041606+PavloNetrebchuk@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:01:26 +0300 Subject: [PATCH 10/38] feat: [FC-0047] Course progress and collapsing sections (#323) * feat: Course Home progress bar * feat: Collapsing course sections * feat: New download icons * feat: show CourseContainerFragment if COURSE_NESTED_LIST_ENABLED false * fix: course progress bar updating * feat: Renamed COURSE_NESTED_LIST_ENABLE feature flag * feat: Course home. Moved certificate access. * chore: enhance app theme capability for prod edX theme/branding (#262) chore: enhance app theme capability for prod edX theme/branding - Integrate Program config updates - theming/branding code improvements for light and dark modes - Force dark mode for the WebView (beta version) - No major change in the Open edX theme fixes: LEARNER-9783 * feat: [FC-0047] Calendar main screen and dialogs (#322) * feat: Created calendar setting screen * feat: CalendarAccessDialog * feat: NewCalendarDialog * fix: Fixes according to PR feedback * fix: DiscussionTopicsViewModelTest.kt jUnit test * fix: assignment dates * feat: [FC-0047] Improved Dashboard Level Navigation (#308) * feat: Created Learn screen. Added course/program navigation. Added endpoint for UserCourses screen. * feat: Added primary course card * feat: Added start/resume course button * feat: Added alignment items * feat: Fix future assignment date, add courses list, add onSearch and onCourse clicks * feat: Add feature flag for enabling new/old dashboard screen, add UserCoursesScreen onClick methods * feat: Create AllEnrolledCoursesFragment. Add endpoint parameters * feat: AllEnrolledCoursesFragment UI * feat: Minor code refactoring, show cached data if no internet connection * feat: UserCourses screen data caching * feat: Dashboard * refactor: Dashboard type flag change, start course button change * feat: Added programs fragment to LearnFragment viewPager * feat: Empty states and settings button * fix: Number of courses * fix: Minor UI changes * fix: Fixes according to designer feedback * fix: Fixes after demo * refactor: Move CourseContainerTab * fix: Fixes according to PR feedback * fix: Fixes according to PR feedback * feat: added a patch from Omer Habib * fix: Fixes according to PR feedback * fix: Assignment date string * fix: Lint error * fix: Assignment date string * fix: Fixes according to PR feedback * fix: Fixes according to designer feedback * fix: Fixes according to PR feedback --------- Co-authored-by: Volodymyr Chekyrta Co-authored-by: Farhan Arshad <43750646+farhan-arshad-dev@users.noreply.github.com> --- Documentation/ConfigurationManagement.md | 2 +- .../java/org/openedx/core/config/UIConfig.kt | 4 +- .../core/data/model/AssignmentProgress.kt | 26 ++ .../java/org/openedx/core/data/model/Block.kt | 35 +- .../core/data/model/CourseStructureModel.kt | 11 +- .../openedx/core/data/model/room/BlockDb.kt | 70 ++-- .../data/model/room/CourseStructureEntity.kt | 8 +- .../core/domain/model/AssignmentProgress.kt | 7 + .../org/openedx/core/domain/model/Block.kt | 5 +- .../core/domain/model/CourseStructure.kt | 3 +- .../org/openedx/core/domain/model/Progress.kt | 9 + .../org/openedx/core/ui/theme/AppColors.kt | 7 +- .../java/org/openedx/core/ui/theme/Theme.kt | 14 +- .../java/org/openedx/core/utils/TimeUtils.kt | 40 +++ core/src/main/res/values/strings.xml | 19 ++ .../org/openedx/core/ui/theme/Colors.kt | 10 +- .../container/CourseContainerFragment.kt | 5 + .../container/CourseContainerViewModel.kt | 2 +- .../dates/CourseDatesViewModel.kt | 2 +- .../outline/CourseOutlineScreen.kt | 234 +++++++------- .../outline/CourseOutlineViewModel.kt | 21 +- .../section/CourseSectionFragment.kt | 8 +- .../course/presentation/ui/CourseUI.kt | 305 +++++++++++------- .../course/presentation/ui/CourseVideosUI.kt | 147 +++------ .../container/CourseUnitContainerViewModel.kt | 2 +- .../videos/CourseVideoViewModel.kt | 35 +- .../res/drawable/course_download_waiting.png | Bin 0 -> 1945 bytes .../res/drawable/course_ic_start_download.xml | 28 +- course/src/main/res/values/strings.xml | 10 + .../container/CourseContainerViewModelTest.kt | 20 +- .../dates/CourseDatesViewModelTest.kt | 1 + .../outline/CourseOutlineViewModelTest.kt | 34 +- .../section/CourseSectionViewModelTest.kt | 21 +- .../CourseUnitContainerViewModelTest.kt | 26 +- .../videos/CourseVideoViewModelTest.kt | 36 ++- .../presentation/DashboardGalleryView.kt | 13 +- dashboard/src/main/res/values/strings.xml | 12 +- default_config/dev/config.yaml | 1 - .../topics/DiscussionTopicsViewModelTest.kt | 22 +- .../presentation/settings/SettingsScreenUI.kt | 2 +- 40 files changed, 770 insertions(+), 487 deletions(-) create mode 100644 core/src/main/java/org/openedx/core/data/model/AssignmentProgress.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/AssignmentProgress.kt create mode 100644 course/src/main/res/drawable/course_download_waiting.png diff --git a/Documentation/ConfigurationManagement.md b/Documentation/ConfigurationManagement.md index b1e21a50b..c3786b1d6 100644 --- a/Documentation/ConfigurationManagement.md +++ b/Documentation/ConfigurationManagement.md @@ -88,7 +88,7 @@ android: - **PRE_LOGIN_EXPERIENCE_ENABLED:** Enables the pre login courses discovery experience. - **WHATS_NEW_ENABLED:** Enables the "What's New" feature to present the latest changes to the user. - **SOCIAL_AUTH_ENABLED:** Enables SSO buttons on the SignIn and SignUp screens. -- **COURSE_NESTED_LIST_ENABLED:** Enables an alternative visual representation for the course structure. +- **COURSE_DROPDOWN_NAVIGATION_ENABLED:** Enables an alternative navigation through units. - **COURSE_UNIT_PROGRESS_ENABLED:** Enables the display of the unit progress within the courseware. ## Future Support diff --git a/core/src/main/java/org/openedx/core/config/UIConfig.kt b/core/src/main/java/org/openedx/core/config/UIConfig.kt index 1f8443d27..86c5d6b2b 100644 --- a/core/src/main/java/org/openedx/core/config/UIConfig.kt +++ b/core/src/main/java/org/openedx/core/config/UIConfig.kt @@ -3,8 +3,8 @@ package org.openedx.core.config import com.google.gson.annotations.SerializedName data class UIConfig( - @SerializedName("COURSE_NESTED_LIST_ENABLED") - val isCourseNestedListEnabled: Boolean = false, + @SerializedName("COURSE_DROPDOWN_NAVIGATION_ENABLED") + val isCourseDropdownNavigationEnabled: Boolean = false, @SerializedName("COURSE_UNIT_PROGRESS_ENABLED") val isCourseUnitProgressEnabled: Boolean = false, ) diff --git a/core/src/main/java/org/openedx/core/data/model/AssignmentProgress.kt b/core/src/main/java/org/openedx/core/data/model/AssignmentProgress.kt new file mode 100644 index 000000000..2ac10cb18 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/AssignmentProgress.kt @@ -0,0 +1,26 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.data.model.room.AssignmentProgressDb +import org.openedx.core.domain.model.AssignmentProgress + +data class AssignmentProgress( + @SerializedName("assignment_type") + val assignmentType: String?, + @SerializedName("num_points_earned") + val numPointsEarned: Float?, + @SerializedName("num_points_possible") + val numPointsPossible: Float?, +) { + fun mapToDomain() = AssignmentProgress( + assignmentType = assignmentType ?: "", + numPointsEarned = numPointsEarned ?: 0f, + numPointsPossible = numPointsPossible ?: 0f + ) + + fun mapToRoomEntity() = AssignmentProgressDb( + assignmentType = assignmentType, + numPointsEarned = numPointsEarned, + numPointsPossible = numPointsPossible + ) +} diff --git a/core/src/main/java/org/openedx/core/data/model/Block.kt b/core/src/main/java/org/openedx/core/data/model/Block.kt index 9c07367ac..b5581209f 100644 --- a/core/src/main/java/org/openedx/core/data/model/Block.kt +++ b/core/src/main/java/org/openedx/core/data/model/Block.kt @@ -2,7 +2,12 @@ package org.openedx.core.data.model import com.google.gson.annotations.SerializedName import org.openedx.core.BlockType -import org.openedx.core.domain.model.Block +import org.openedx.core.utils.TimeUtils +import org.openedx.core.domain.model.Block as DomainBlock +import org.openedx.core.domain.model.BlockCounts as DomainBlockCounts +import org.openedx.core.domain.model.EncodedVideos as DomainEncodedVideos +import org.openedx.core.domain.model.StudentViewData as DomainStudentViewData +import org.openedx.core.domain.model.VideoInfo as DomainVideoInfo data class Block( @SerializedName("id") @@ -33,8 +38,12 @@ data class Block( val completion: Double?, @SerializedName("contains_gated_content") val containsGatedContent: Boolean?, + @SerializedName("assignment_progress") + val assignmentProgress: AssignmentProgress?, + @SerializedName("due") + val due: String? ) { - fun mapToDomain(blockData: Map): Block { + fun mapToDomain(blockData: Map): DomainBlock { val blockType = BlockType.getBlockType(type ?: "") val descendantsType = if (blockType == BlockType.VERTICAL) { val types = descendants?.map { descendant -> @@ -46,7 +55,7 @@ data class Block( blockType } - return org.openedx.core.domain.model.Block( + return DomainBlock( id = id ?: "", blockId = blockId ?: "", lmsWebUrl = lmsWebUrl ?: "", @@ -61,7 +70,9 @@ data class Block( studentViewMultiDevice = studentViewMultiDevice ?: false, blockCounts = blockCounts?.mapToDomain()!!, completion = completion ?: 0.0, - containsGatedContent = containsGatedContent ?: false + containsGatedContent = containsGatedContent ?: false, + assignmentProgress = assignmentProgress?.mapToDomain(), + due = TimeUtils.iso8601ToDate(due ?: ""), ) } } @@ -80,8 +91,8 @@ data class StudentViewData( @SerializedName("topic_id") val topicId: String? ) { - fun mapToDomain(): org.openedx.core.domain.model.StudentViewData { - return org.openedx.core.domain.model.StudentViewData( + fun mapToDomain(): DomainStudentViewData { + return DomainStudentViewData( onlyOnWeb = onlyOnWeb ?: false, duration = duration ?: "", transcripts = transcripts, @@ -106,8 +117,8 @@ data class EncodedVideos( var mobileLow: VideoInfo? ) { - fun mapToDomain(): org.openedx.core.domain.model.EncodedVideos { - return org.openedx.core.domain.model.EncodedVideos( + fun mapToDomain(): DomainEncodedVideos { + return DomainEncodedVideos( youtube = videoInfo?.mapToDomain(), hls = hls?.mapToDomain(), fallback = fallback?.mapToDomain(), @@ -124,8 +135,8 @@ data class VideoInfo( @SerializedName("file_size") var fileSize: Int? ) { - fun mapToDomain(): org.openedx.core.domain.model.VideoInfo { - return org.openedx.core.domain.model.VideoInfo( + fun mapToDomain(): DomainVideoInfo { + return DomainVideoInfo( url = url ?: "", fileSize = fileSize ?: 0 ) @@ -136,8 +147,8 @@ data class BlockCounts( @SerializedName("video") var video: Int? ) { - fun mapToDomain(): org.openedx.core.domain.model.BlockCounts { - return org.openedx.core.domain.model.BlockCounts( + fun mapToDomain(): DomainBlockCounts { + return DomainBlockCounts( video = video ?: 0 ) } diff --git a/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt b/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt index 9f22a14a0..d09411d14 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt @@ -4,6 +4,7 @@ import com.google.gson.annotations.SerializedName import org.openedx.core.data.model.room.BlockDb import org.openedx.core.data.model.room.CourseStructureEntity import org.openedx.core.data.model.room.MediaDb +import org.openedx.core.data.model.room.discovery.ProgressDb import org.openedx.core.domain.model.CourseStructure import org.openedx.core.utils.TimeUtils @@ -35,7 +36,9 @@ data class CourseStructureModel( @SerializedName("certificate") val certificate: Certificate?, @SerializedName("is_self_paced") - var isSelfPaced: Boolean? + var isSelfPaced: Boolean?, + @SerializedName("course_progress") + val progress: Progress?, ) { fun mapToDomain(): CourseStructure { return CourseStructure( @@ -54,7 +57,8 @@ data class CourseStructureModel( coursewareAccess = coursewareAccess?.mapToDomain(), media = media?.mapToDomain(), certificate = certificate?.mapToDomain(), - isSelfPaced = isSelfPaced ?: false + isSelfPaced = isSelfPaced ?: false, + progress = progress?.mapToDomain() ) } @@ -73,7 +77,8 @@ data class CourseStructureModel( coursewareAccess = coursewareAccess?.mapToRoomEntity(), media = MediaDb.createFrom(media), certificate = certificate?.mapToRoomEntity(), - isSelfPaced = isSelfPaced ?: false + isSelfPaced = isSelfPaced ?: false, + progress = progress?.mapToRoomEntity() ?: ProgressDb.DEFAULT_PROGRESS ) } } diff --git a/core/src/main/java/org/openedx/core/data/model/room/BlockDb.kt b/core/src/main/java/org/openedx/core/data/model/room/BlockDb.kt index b1e9a53cf..737437dd0 100644 --- a/core/src/main/java/org/openedx/core/data/model/room/BlockDb.kt +++ b/core/src/main/java/org/openedx/core/data/model/room/BlockDb.kt @@ -3,7 +3,18 @@ package org.openedx.core.data.model.room import androidx.room.ColumnInfo import androidx.room.Embedded import org.openedx.core.BlockType -import org.openedx.core.domain.model.* +import org.openedx.core.data.model.Block +import org.openedx.core.data.model.BlockCounts +import org.openedx.core.data.model.EncodedVideos +import org.openedx.core.data.model.StudentViewData +import org.openedx.core.data.model.VideoInfo +import org.openedx.core.utils.TimeUtils +import org.openedx.core.domain.model.AssignmentProgress as DomainAssignmentProgress +import org.openedx.core.domain.model.Block as DomainBlock +import org.openedx.core.domain.model.BlockCounts as DomainBlockCounts +import org.openedx.core.domain.model.EncodedVideos as DomainEncodedVideos +import org.openedx.core.domain.model.StudentViewData as DomainStudentViewData +import org.openedx.core.domain.model.VideoInfo as DomainVideoInfo data class BlockDb( @ColumnInfo("id") @@ -33,9 +44,13 @@ data class BlockDb( @ColumnInfo("completion") val completion: Double, @ColumnInfo("contains_gated_content") - val containsGatedContent: Boolean + val containsGatedContent: Boolean, + @Embedded + val assignmentProgress: AssignmentProgressDb?, + @ColumnInfo("due") + val due: String? ) { - fun mapToDomain(blocks: List): Block { + fun mapToDomain(blocks: List): DomainBlock { val blockType = BlockType.getBlockType(type) val descendantsType = if (blockType == BlockType.VERTICAL) { val types = descendants.map { descendant -> @@ -47,7 +62,7 @@ data class BlockDb( blockType } - return Block( + return DomainBlock( id = id, blockId = blockId, lmsWebUrl = lmsWebUrl, @@ -62,14 +77,16 @@ data class BlockDb( descendants = descendants, descendantsType = descendantsType, completion = completion, - containsGatedContent = containsGatedContent + containsGatedContent = containsGatedContent, + assignmentProgress = assignmentProgress?.mapToDomain(), + due = TimeUtils.iso8601ToDate(due ?: ""), ) } companion object { fun createFrom( - block: org.openedx.core.data.model.Block + block: Block ): BlockDb { with(block) { return BlockDb( @@ -86,7 +103,9 @@ data class BlockDb( studentViewMultiDevice = studentViewMultiDevice ?: false, blockCounts = BlockCountsDb.createFrom(blockCounts), completion = completion ?: 0.0, - containsGatedContent = containsGatedContent ?: false + containsGatedContent = containsGatedContent ?: false, + assignmentProgress = assignmentProgress?.mapToRoomEntity(), + due = due ) } } @@ -105,8 +124,8 @@ data class StudentViewDataDb( @Embedded val encodedVideos: EncodedVideosDb? ) { - fun mapToDomain(): StudentViewData { - return StudentViewData( + fun mapToDomain(): DomainStudentViewData { + return DomainStudentViewData( onlyOnWeb, duration, transcripts, @@ -117,7 +136,7 @@ data class StudentViewDataDb( companion object { - fun createFrom(studentViewData: org.openedx.core.data.model.StudentViewData?): StudentViewDataDb { + fun createFrom(studentViewData: StudentViewData?): StudentViewDataDb { return StudentViewDataDb( onlyOnWeb = studentViewData?.onlyOnWeb ?: false, duration = studentViewData?.duration.toString(), @@ -144,9 +163,9 @@ data class EncodedVideosDb( @ColumnInfo("mobileLow") var mobileLow: VideoInfoDb? ) { - fun mapToDomain(): EncodedVideos { - return EncodedVideos( - youtube?.mapToDomain(), + fun mapToDomain(): DomainEncodedVideos { + return DomainEncodedVideos( + youtube = youtube?.mapToDomain(), hls = hls?.mapToDomain(), fallback = fallback?.mapToDomain(), desktopMp4 = desktopMp4?.mapToDomain(), @@ -156,7 +175,7 @@ data class EncodedVideosDb( } companion object { - fun createFrom(encodedVideos: org.openedx.core.data.model.EncodedVideos?): EncodedVideosDb { + fun createFrom(encodedVideos: EncodedVideos?): EncodedVideosDb { return EncodedVideosDb( youtube = VideoInfoDb.createFrom(encodedVideos?.videoInfo), hls = VideoInfoDb.createFrom(encodedVideos?.hls), @@ -176,10 +195,10 @@ data class VideoInfoDb( @ColumnInfo("fileSize") val fileSize: Int ) { - fun mapToDomain() = VideoInfo(url, fileSize) + fun mapToDomain() = DomainVideoInfo(url, fileSize) companion object { - fun createFrom(videoInfo: org.openedx.core.data.model.VideoInfo?): VideoInfoDb? { + fun createFrom(videoInfo: VideoInfo?): VideoInfoDb? { if (videoInfo == null) return null return VideoInfoDb( videoInfo.url ?: "", @@ -193,11 +212,26 @@ data class BlockCountsDb( @ColumnInfo("video") val video: Int ) { - fun mapToDomain() = BlockCounts(video) + fun mapToDomain() = DomainBlockCounts(video) companion object { - fun createFrom(blocksCounts: org.openedx.core.data.model.BlockCounts?): BlockCountsDb { + fun createFrom(blocksCounts: BlockCounts?): BlockCountsDb { return BlockCountsDb(blocksCounts?.video ?: 0) } } } + +data class AssignmentProgressDb( + @ColumnInfo("assignment_type") + val assignmentType: String?, + @ColumnInfo("num_points_earned") + val numPointsEarned: Float?, + @ColumnInfo("num_points_possible") + val numPointsPossible: Float?, +) { + fun mapToDomain() = DomainAssignmentProgress( + assignmentType = assignmentType ?: "", + numPointsEarned = numPointsEarned ?: 0f, + numPointsPossible = numPointsPossible ?: 0f + ) +} diff --git a/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt b/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt index 90352d821..49862d683 100644 --- a/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt +++ b/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt @@ -6,6 +6,7 @@ import androidx.room.Entity import androidx.room.PrimaryKey import org.openedx.core.data.model.room.discovery.CertificateDb import org.openedx.core.data.model.room.discovery.CoursewareAccessDb +import org.openedx.core.data.model.room.discovery.ProgressDb import org.openedx.core.domain.model.CourseStructure import org.openedx.core.utils.TimeUtils @@ -39,7 +40,9 @@ data class CourseStructureEntity( @Embedded val certificate: CertificateDb?, @ColumnInfo("isSelfPaced") - val isSelfPaced: Boolean + val isSelfPaced: Boolean, + @Embedded + val progress: ProgressDb, ) { fun mapToDomain(): CourseStructure { @@ -57,7 +60,8 @@ data class CourseStructureEntity( coursewareAccess?.mapToDomain(), media?.mapToDomain(), certificate?.mapToDomain(), - isSelfPaced + isSelfPaced, + progress.mapToDomain() ) } diff --git a/core/src/main/java/org/openedx/core/domain/model/AssignmentProgress.kt b/core/src/main/java/org/openedx/core/domain/model/AssignmentProgress.kt new file mode 100644 index 000000000..659665bfe --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/AssignmentProgress.kt @@ -0,0 +1,7 @@ +package org.openedx.core.domain.model + +data class AssignmentProgress( + val assignmentType: String, + val numPointsEarned: Float, + val numPointsPossible: Float +) diff --git a/core/src/main/java/org/openedx/core/domain/model/Block.kt b/core/src/main/java/org/openedx/core/domain/model/Block.kt index 2f1766ecb..460f283ba 100644 --- a/core/src/main/java/org/openedx/core/domain/model/Block.kt +++ b/core/src/main/java/org/openedx/core/domain/model/Block.kt @@ -7,6 +7,7 @@ import org.openedx.core.module.db.DownloadModel import org.openedx.core.module.db.DownloadedState import org.openedx.core.module.db.FileType import org.openedx.core.utils.VideoUtil +import java.util.Date data class Block( @@ -25,7 +26,9 @@ data class Block( val descendantsType: BlockType, val completion: Double, val containsGatedContent: Boolean = false, - val downloadModel: DownloadModel? = null + val downloadModel: DownloadModel? = null, + val assignmentProgress: AssignmentProgress?, + val due: Date? ) { val isDownloadable: Boolean get() { diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt b/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt index bdb3820de..4ba3a8419 100644 --- a/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt +++ b/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt @@ -16,5 +16,6 @@ data class CourseStructure( val coursewareAccess: CoursewareAccess?, val media: Media?, val certificate: Certificate?, - val isSelfPaced: Boolean + val isSelfPaced: Boolean, + val progress: Progress?, ) diff --git a/core/src/main/java/org/openedx/core/domain/model/Progress.kt b/core/src/main/java/org/openedx/core/domain/model/Progress.kt index 5d8ea19f8..800a9c292 100644 --- a/core/src/main/java/org/openedx/core/domain/model/Progress.kt +++ b/core/src/main/java/org/openedx/core/domain/model/Progress.kt @@ -1,6 +1,7 @@ package org.openedx.core.domain.model import android.os.Parcelable +import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize @Parcelize @@ -8,6 +9,14 @@ data class Progress( val assignmentsCompleted: Int, val totalAssignmentsCount: Int, ) : Parcelable { + + @IgnoredOnParcel + val value: Float = try { + assignmentsCompleted.toFloat() / totalAssignmentsCount.toFloat() + } catch (_: ArithmeticException) { + 0f + } + companion object { val DEFAULT_PROGRESS = Progress(0, 0) } diff --git a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt index 968fd9fe3..625c52b27 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt @@ -50,7 +50,7 @@ data class AppColors( val inactiveButtonBackground: Color, val inactiveButtonText: Color, - val accessGreen: Color, + val successGreen: Color, val datesSectionBarPastDue: Color, val datesSectionBarToday: Color, @@ -73,7 +73,10 @@ data class AppColors( val courseHomeHeaderShade: Color, val courseHomeBackBtnBackground: Color, - val settingsTitleContent: Color + val settingsTitleContent: Color, + + val progressBarColor: Color, + val progressBarBackgroundColor: Color ) { val primary: Color get() = material.primary val primaryVariant: Color get() = material.primaryVariant diff --git a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt index 291192c1c..88c973105 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt @@ -68,7 +68,7 @@ private val DarkColorPalette = AppColors( inactiveButtonBackground = dark_inactive_button_background, inactiveButtonText = dark_primary_button_text, - accessGreen = dark_access_green, + successGreen = dark_success_green, datesSectionBarPastDue = dark_dates_section_bar_past_due, datesSectionBarToday = dark_dates_section_bar_today, @@ -91,7 +91,10 @@ private val DarkColorPalette = AppColors( courseHomeHeaderShade = dark_course_home_header_shade, courseHomeBackBtnBackground = dark_course_home_back_btn_background, - settingsTitleContent = dark_settings_title_content + settingsTitleContent = dark_settings_title_content, + + progressBarColor = dark_progress_bar_color, + progressBarBackgroundColor = dark_progress_bar_background_color ) private val LightColorPalette = AppColors( @@ -152,7 +155,7 @@ private val LightColorPalette = AppColors( inactiveButtonBackground = light_inactive_button_background, inactiveButtonText = light_primary_button_text, - accessGreen = light_access_green, + successGreen = light_success_green, datesSectionBarPastDue = light_dates_section_bar_past_due, datesSectionBarToday = light_dates_section_bar_today, @@ -175,7 +178,10 @@ private val LightColorPalette = AppColors( courseHomeHeaderShade = light_course_home_header_shade, courseHomeBackBtnBackground = light_course_home_back_btn_background, - settingsTitleContent = light_settings_title_content + settingsTitleContent = light_settings_title_content, + + progressBarColor = light_progress_bar_color, + progressBarBackgroundColor = light_progress_bar_background_color ) val MaterialTheme.appColors: AppColors diff --git a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt index 9ccfaebef..5327b8cf5 100644 --- a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt +++ b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt @@ -242,6 +242,46 @@ object TimeUtils { } } + fun getAssignmentFormattedDate(context: Context, date: Date): String { + val inputDate = Calendar.getInstance().also { + it.time = date + it.clearTimeComponents() + } + val daysDifference = getDayDifference(inputDate) + + return when { + daysDifference == 0 -> { + context.getString(R.string.core_date_format_assignment_due_today) + } + + daysDifference == 1 -> { + context.getString(R.string.core_date_format_assignment_due_tomorrow) + } + + daysDifference == -1 -> { + context.getString(R.string.core_date_format_assignment_due_yesterday) + } + + daysDifference <= -2 -> { + val numberOfDays = ceil(-daysDifference.toDouble()).toInt() + context.resources.getQuantityString( + R.plurals.core_date_format_assignment_due_days_ago, + numberOfDays, + numberOfDays + ) + } + + else -> { + val numberOfDays = ceil(daysDifference.toDouble()).toInt() + context.resources.getQuantityString( + R.plurals.core_date_format_assignment_due_in, + numberOfDays, + numberOfDays + ) + } + } + } + /** * Returns the number of days difference between the given date and the current date. */ diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index afbc28243..580d262ac 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -96,6 +96,25 @@ Tomorrow Yesterday %1$s days ago + Due Today + Due Tomorrow + Due Yesterday + + Due %1$d days ago + Due %1$d day ago + Due %1$d days ago + Due %1$d days ago + Due %1$d days ago + Due %1$d days ago + + + Due in %1$d days + Due in %1$d day + Due in %1$d days + Due in %1$d days + Due in %1$d days + Due in %1$d days + %d Item Hidden %d Items Hidden diff --git a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt index 0bb1114c8..855d557d3 100644 --- a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt @@ -51,7 +51,7 @@ val light_warning = Color(0xFFFFC94D) val light_info = Color(0xFF42AAFF) val light_rate_stars = Color(0xFFFFC94D) val light_inactive_button_background = Color(0xFFCCD4E0) -val light_access_green = Color(0xFF23BCA0) +val light_success_green = Color(0xFF198571) val light_dates_section_bar_past_due = light_warning val light_dates_section_bar_today = light_info val light_dates_section_bar_this_week = light_text_primary_variant @@ -70,9 +70,11 @@ val light_tab_selected_btn_content = Color.White val light_course_home_header_shade = Color(0xFFBABABA) val light_course_home_back_btn_background = Color.White val light_settings_title_content = Color.White +val light_progress_bar_color = light_primary +val light_progress_bar_background_color = Color(0xFF97A5BB) -val dark_primary = Color(0xFF5478F9) +val dark_primary = Color(0xFF3F68F8) val dark_primary_variant = Color(0xFF3700B3) val dark_secondary = Color(0xFF03DAC6) val dark_secondary_variant = Color(0xFF373E4F) @@ -121,7 +123,7 @@ val dark_info_variant = Color(0xFF5478F9) val dark_onInfo = Color.White val dark_rate_stars = Color(0xFFFFC94D) val dark_inactive_button_background = Color(0xFFCCD4E0) -val dark_access_green = Color(0xFF23BCA0) +val dark_success_green = Color(0xFF198571) val dark_dates_section_bar_past_due = dark_warning val dark_dates_section_bar_today = dark_info val dark_dates_section_bar_this_week = dark_text_primary_variant @@ -140,3 +142,5 @@ val dark_tab_selected_btn_content = Color.White val dark_course_home_header_shade = Color(0xFF999999) val dark_course_home_back_btn_background = Color.Black val dark_settings_title_content = Color.White +val dark_progress_bar_color = light_primary +val dark_progress_bar_background_color = Color(0xFF8E9BAE) 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 a55ca6bc9..4df1fcf64 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 @@ -113,6 +113,11 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { observe() } + override fun onResume() { + super.onResume() + viewModel.updateData() + } + override fun onDestroyView() { snackBar?.dismiss() super.onDestroyView() 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 bbc26d535..4e233e3d7 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 @@ -169,7 +169,7 @@ class CourseContainerViewModel( _showProgress.value = true viewModelScope.launch { try { - val courseStructure = interactor.getCourseStructure(courseId) + val courseStructure = interactor.getCourseStructure(courseId, true) courseName = courseStructure.name _organization = courseStructure.org _isSelfPaced = courseStructure.isSelfPaced 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 a6a78cb72..4d6236b67 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 @@ -77,7 +77,7 @@ class CourseDatesViewModel( private var courseBannerType: CourseBannerType = CourseBannerType.BLANK private var courseStructure: CourseStructure? = null - val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled + val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseDropdownNavigationEnabled init { viewModelScope.launch { diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt index 9903578dc..1a29819f2 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt @@ -2,7 +2,6 @@ package org.openedx.course.presentation.outline import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -17,9 +16,9 @@ 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.Divider +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.Icon +import androidx.compose.material.LinearProgressIndicator import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.Surface @@ -33,9 +32,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.AndroidUriHandler import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Devices @@ -45,11 +46,13 @@ import androidx.compose.ui.unit.dp import androidx.fragment.app.FragmentManager import org.openedx.core.BlockType import org.openedx.core.UIMessage +import org.openedx.core.domain.model.AssignmentProgress 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.domain.model.Progress import org.openedx.core.extension.takeIfNotEmpty import org.openedx.core.presentation.course.CourseViewMode import org.openedx.core.ui.HandleUIMessage @@ -66,10 +69,8 @@ import org.openedx.core.utils.FileUtil import org.openedx.course.R 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.CourseMessage -import org.openedx.course.presentation.ui.CourseSectionCard -import org.openedx.course.presentation.ui.CourseSubSectionItem +import org.openedx.course.presentation.ui.CourseSection import java.util.Date import org.openedx.core.R as CoreR @@ -94,20 +95,7 @@ fun CourseOutlineScreen( CourseOutlineUI( windowSize = windowSize, uiState = uiState, - isCourseNestedListEnabled = viewModel.isCourseNestedListEnabled, uiMessage = uiMessage, - onItemClick = { block -> - viewModel.sequentialClickedEvent( - block.blockId, - block.displayName - ) - viewModel.courseRouter.navigateToCourseSubsections( - fm = fragmentManager, - courseId = viewModel.courseId, - subSectionId = block.id, - mode = CourseViewMode.FULL - ) - }, onExpandClick = { block -> if (viewModel.switchCourseSections(block.id)) { viewModel.sequentialClickedEvent( @@ -117,15 +105,28 @@ fun CourseOutlineScreen( } }, onSubSectionClick = { subSectionBlock -> - viewModel.courseSubSectionUnit[subSectionBlock.id]?.let { unit -> - viewModel.logUnitDetailViewedEvent( - unit.blockId, - unit.displayName + if (viewModel.isCourseNestedListEnabled) { + viewModel.courseSubSectionUnit[subSectionBlock.id]?.let { unit -> + viewModel.logUnitDetailViewedEvent( + unit.blockId, + unit.displayName + ) + viewModel.courseRouter.navigateToCourseContainer( + fragmentManager, + courseId = viewModel.courseId, + unitId = unit.id, + mode = CourseViewMode.FULL + ) + } + } else { + viewModel.sequentialClickedEvent( + subSectionBlock.blockId, + subSectionBlock.displayName ) - viewModel.courseRouter.navigateToCourseContainer( - fragmentManager, + viewModel.courseRouter.navigateToCourseSubsections( + fm = fragmentManager, courseId = viewModel.courseId, - unitId = unit.id, + subSectionId = subSectionBlock.id, mode = CourseViewMode.FULL ) } @@ -136,19 +137,21 @@ fun CourseOutlineScreen( componentId ) }, - onDownloadClick = { - if (viewModel.isBlockDownloading(it.id)) { - viewModel.courseRouter.navigateToDownloadQueue( - fm = fragmentManager, - viewModel.getDownloadableChildren(it.id) - ?: arrayListOf() - ) - } else if (viewModel.isBlockDownloaded(it.id)) { - viewModel.removeDownloadModels(it.id) - } else { - viewModel.saveDownloadModels( - FileUtil(context).getExternalAppDir().path, it.id - ) + onDownloadClick = { blocksIds -> + blocksIds.forEach { blockId -> + if (viewModel.isBlockDownloading(blockId)) { + viewModel.courseRouter.navigateToDownloadQueue( + fm = fragmentManager, + viewModel.getDownloadableChildren(blockId) + ?: arrayListOf() + ) + } else if (viewModel.isBlockDownloaded(blockId)) { + viewModel.removeDownloadModels(blockId) + } else { + viewModel.saveDownloadModels( + FileUtil(context).getExternalAppDir().path, blockId + ) + } } }, onResetDatesClick = { @@ -170,13 +173,11 @@ fun CourseOutlineScreen( private fun CourseOutlineUI( windowSize: WindowSize, uiState: CourseOutlineUIState, - isCourseNestedListEnabled: Boolean, uiMessage: UIMessage?, - onItemClick: (Block) -> Unit, onExpandClick: (Block) -> Unit, onSubSectionClick: (Block) -> Unit, onResumeClick: (String) -> Unit, - onDownloadClick: (Block) -> Unit, + onDownloadClick: (blockIds: List) -> Unit, onResetDatesClick: () -> Unit, onCertificateClick: (String) -> Unit, ) { @@ -278,6 +279,19 @@ private fun CourseOutlineUI( } } + + val progress = uiState.courseStructure.progress + if (progress != null && progress.totalAssignmentsCount > 0) { + item { + CourseProgress( + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp, start = 24.dp, end = 24.dp), + progress = progress + ) + } + } + if (uiState.resumeComponent != null) { item { Box(listPadding) { @@ -298,75 +312,26 @@ private fun CourseOutlineUI( } } - if (isCourseNestedListEnabled) { - uiState.courseStructure.blockData.forEach { section -> - val courseSubSections = - uiState.courseSubSections[section.id] - val courseSectionsState = - uiState.courseSectionsState[section.id] - - item { - Column { - CourseExpandableChapterCard( - modifier = listPadding, - block = section, - onItemClick = onExpandClick, - arrowDegrees = if (courseSectionsState == true) -90f else 90f - ) - Divider() - } - } - - courseSubSections?.forEach { subSectionBlock -> - item { - Column { - AnimatedVisibility( - visible = courseSectionsState == true - ) { - Column { - val downloadsCount = - uiState.subSectionsDownloadsCount[subSectionBlock.id] - ?: 0 - - CourseSubSectionItem( - modifier = listPadding, - block = subSectionBlock, - downloadedState = uiState.downloadedState[subSectionBlock.id], - downloadsCount = downloadsCount, - onClick = onSubSectionClick, - onDownloadClick = onDownloadClick - ) - Divider() - } - } - } - } - } - } - return@LazyColumn + item { + Spacer(modifier = Modifier.height(12.dp)) } + uiState.courseStructure.blockData.forEach { section -> + val courseSubSections = + uiState.courseSubSections[section.id] + val courseSectionsState = + uiState.courseSectionsState[section.id] - items(uiState.courseStructure.blockData) { block -> - Column(listPadding) { - if (block.type == BlockType.CHAPTER) { - Text( - modifier = Modifier.padding( - top = 36.dp, - bottom = 8.dp - ), - text = block.displayName, - style = MaterialTheme.appTypography.titleMedium, - color = MaterialTheme.appColors.textPrimaryVariant - ) - } else { - CourseSectionCard( - block = block, - downloadedState = uiState.downloadedState[block.id], - onItemClick = onItemClick, - onDownloadClick = onDownloadClick - ) - Divider() - } + item { + CourseSection( + modifier = listPadding.padding(vertical = 4.dp), + block = section, + onItemClick = onExpandClick, + courseSectionsState = courseSectionsState, + courseSubSections = courseSubSections, + downloadedStateMap = uiState.downloadedState, + onSubSectionClick = onSubSectionClick, + onDownloadClick = onDownloadClick + ) } } } @@ -490,6 +455,37 @@ private fun ResumeCourseTablet( } } +@Composable +private fun CourseProgress( + modifier: Modifier = Modifier, + progress: Progress +) { + Column( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + LinearProgressIndicator( + modifier = Modifier + .fillMaxWidth() + .height(10.dp) + .clip(CircleShape), + progress = progress.value, + color = MaterialTheme.appColors.progressBarColor, + backgroundColor = MaterialTheme.appColors.progressBarBackgroundColor + ) + Text( + text = pluralStringResource( + R.plurals.course_assignments_complete, + progress.assignmentsCompleted, + progress.assignmentsCompleted, + progress.totalAssignmentsCount + ), + color = MaterialTheme.appColors.textDark, + style = MaterialTheme.appTypography.labelSmall + ) + } +} + fun getUnitBlockIcon(block: Block): Int { return when (block.type) { BlockType.VIDEO -> R.drawable.ic_course_video @@ -521,9 +517,7 @@ private fun CourseOutlineScreenPreview() { hasEnded = false ) ), - isCourseNestedListEnabled = true, uiMessage = null, - onItemClick = {}, onExpandClick = {}, onSubSectionClick = {}, onResumeClick = {}, @@ -556,9 +550,7 @@ private fun CourseOutlineScreenTabletPreview() { hasEnded = false ) ), - isCourseNestedListEnabled = true, uiMessage = null, - onItemClick = {}, onExpandClick = {}, onSubSectionClick = {}, onResumeClick = {}, @@ -578,6 +570,11 @@ private fun ResumeCoursePreview() { } } +private val mockAssignmentProgress = AssignmentProgress( + assignmentType = "Home", + numPointsEarned = 1f, + numPointsPossible = 3f +) private val mockChapterBlock = Block( id = "id", blockId = "blockId", @@ -593,7 +590,9 @@ private val mockChapterBlock = Block( descendants = emptyList(), descendantsType = BlockType.CHAPTER, completion = 0.0, - containsGatedContent = false + containsGatedContent = false, + assignmentProgress = mockAssignmentProgress, + due = Date() ) private val mockSequentialBlock = Block( id = "id", @@ -610,7 +609,9 @@ private val mockSequentialBlock = Block( descendants = emptyList(), descendantsType = BlockType.CHAPTER, completion = 0.0, - containsGatedContent = false + containsGatedContent = false, + assignmentProgress = mockAssignmentProgress, + due = Date() ) private val mockCourseStructure = CourseStructure( @@ -634,5 +635,6 @@ private val mockCourseStructure = CourseStructure( ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = Progress(1, 3) ) 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 11ec94d95..602c7d2fa 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 @@ -64,7 +64,7 @@ class CourseOutlineViewModel( workerController, coreAnalytics ) { - val isCourseNestedListEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled + val isCourseNestedListEnabled get() = config.getCourseUIConfig().isCourseDropdownNavigationEnabled private val _uiState = MutableStateFlow(CourseOutlineUIState.Loading) val uiState: StateFlow @@ -81,7 +81,7 @@ class CourseOutlineViewModel( private var resumeSectionBlock: Block? = null private var resumeVerticalBlock: Block? = null - private val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled + private val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseDropdownNavigationEnabled private val courseSubSections = mutableMapOf>() private val subSectionsDownloadsCount = mutableMapOf() @@ -239,17 +239,12 @@ class CourseOutlineViewModel( resultBlocks.add(block) block.descendants.forEach { descendant -> blocks.find { it.id == descendant }?.let { sequentialBlock -> - if (isCourseNestedListEnabled) { - courseSubSections.getOrPut(block.id) { mutableListOf() } - .add(sequentialBlock) - courseSubSectionUnit[sequentialBlock.id] = - sequentialBlock.getFirstDescendantBlock(blocks) - subSectionsDownloadsCount[sequentialBlock.id] = - sequentialBlock.getDownloadsCount(blocks) - - } else { - resultBlocks.add(sequentialBlock) - } + courseSubSections.getOrPut(block.id) { mutableListOf() } + .add(sequentialBlock) + courseSubSectionUnit[sequentialBlock.id] = + sequentialBlock.getFirstDescendantBlock(blocks) + subSectionsDownloadsCount[sequentialBlock.id] = + sequentialBlock.getDownloadsCount(blocks) addDownloadableChildrenForSequentialBlock(sequentialBlock) } } diff --git a/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt b/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt index 6a1a1bf9e..0c83b264b 100644 --- a/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/section/CourseSectionFragment.kt @@ -61,6 +61,7 @@ import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import org.openedx.core.BlockType import org.openedx.core.UIMessage +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.extension.serializable @@ -78,10 +79,13 @@ import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appShapes import org.openedx.core.ui.theme.appTypography import org.openedx.core.ui.windowSizeValue +import org.openedx.core.ui.windowSizeValue import org.openedx.core.utils.FileUtil import org.openedx.course.R import org.openedx.course.presentation.CourseRouter import org.openedx.course.presentation.ui.CardArrow +import java.io.File +import java.util.Date import org.openedx.core.R as CoreR class CourseSectionFragment : Fragment() { @@ -476,5 +480,7 @@ private val mockBlock = Block( descendants = emptyList(), descendantsType = BlockType.HTML, completion = 0.0, - containsGatedContent = false + containsGatedContent = false, + assignmentProgress = AssignmentProgress("", 1f, 2f), + due = Date() ) 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 6a89c1dc2..27da57afb 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 @@ -1,8 +1,10 @@ package org.openedx.course.presentation.ui import android.content.res.Configuration +import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image @@ -44,12 +46,15 @@ import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.CloudDone import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableLongStateOf +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 @@ -58,7 +63,9 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics @@ -72,6 +79,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import org.jsoup.Jsoup import org.openedx.core.BlockType +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseDatesBannerInfo @@ -90,6 +98,7 @@ import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appShapes import org.openedx.core.ui.theme.appTypography +import org.openedx.core.utils.TimeUtils import org.openedx.course.R import org.openedx.course.presentation.dates.mockedCourseBannerInfo import org.openedx.course.presentation.outline.getUnitBlockIcon @@ -276,7 +285,7 @@ fun CardArrow( ) { Icon( imageVector = Icons.Filled.ChevronRight, - tint = MaterialTheme.appColors.primary, + tint = MaterialTheme.appColors.textDark, contentDescription = "Expandable Arrow", modifier = Modifier.rotate(degrees), ) @@ -573,81 +582,181 @@ fun VideoSubtitles( } @Composable -fun CourseExpandableChapterCard( - modifier: Modifier, +fun CourseSection( + modifier: Modifier = Modifier, block: Block, onItemClick: (Block) -> Unit, + courseSectionsState: Boolean?, + courseSubSections: List?, + downloadedStateMap: Map, + onSubSectionClick: (Block) -> Unit, + onDownloadClick: (blocksIds: List) -> Unit, +) { + val arrowRotation by animateFloatAsState( + targetValue = if (courseSectionsState == true) -90f else 90f, label = "" + ) + val sectionIds = courseSubSections?.map { it.id }.orEmpty() + val filteredStatuses = downloadedStateMap.filterKeys { it in sectionIds }.values + val downloadedState = when { + filteredStatuses.isEmpty() -> null + filteredStatuses.all { it.isDownloaded } -> DownloadedState.DOWNLOADED + filteredStatuses.any { it.isWaitingOrDownloading } -> DownloadedState.DOWNLOADING + else -> DownloadedState.NOT_DOWNLOADED + } + + Column(modifier = modifier + .clip(MaterialTheme.appShapes.cardShape) + .noRippleClickable { onItemClick(block) } + .background(MaterialTheme.appColors.cardViewBackground) + .border( + 1.dp, + MaterialTheme.appColors.cardViewBorder, + MaterialTheme.appShapes.cardShape + ) + ) { + CourseExpandableChapterCard( + block = block, + arrowDegrees = arrowRotation, + downloadedState = downloadedState, + onDownloadClick = { + onDownloadClick(downloadedStateMap.keys.toList()) + } + ) + courseSubSections?.forEach { subSectionBlock -> + AnimatedVisibility( + visible = courseSectionsState == true + ) { + CourseSubSectionItem( + block = subSectionBlock, + onClick = onSubSectionClick + ) + } + } + } +} + +@Composable +fun CourseExpandableChapterCard( + modifier: Modifier = Modifier, + block: Block, arrowDegrees: Float = 0f, + downloadedState: DownloadedState?, + onDownloadClick: () -> Unit, ) { - Column(modifier = Modifier - .clickable { onItemClick(block) } - .background(if (block.isCompleted()) MaterialTheme.appColors.surface else Color.Transparent) + val iconModifier = Modifier.size(24.dp) + Row( + modifier + .fillMaxWidth() + .height(48.dp) + .padding(vertical = 8.dp) + .padding(start = 16.dp, end = 16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { + CardArrow(degrees = arrowDegrees) + if (block.isCompleted()) { + val completedIconPainter = painterResource(R.drawable.course_ic_task_alt) + val completedIconColor = MaterialTheme.appColors.successGreen + val completedIconDescription = stringResource(id = R.string.course_accessibility_section_completed) + + Icon( + painter = completedIconPainter, + contentDescription = completedIconDescription, + tint = completedIconColor + ) + } + Text( + modifier = Modifier.weight(1f), + text = block.displayName, + style = MaterialTheme.appTypography.titleSmall, + color = MaterialTheme.appColors.textPrimary, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) Row( - modifier - .fillMaxWidth() - .height(60.dp) - .padding( - vertical = 8.dp - ), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween + modifier = Modifier.fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically ) { - if (block.isCompleted()) { - val completedIconPainter = painterResource(R.drawable.course_ic_task_alt) - val completedIconColor = MaterialTheme.appColors.primary - val completedIconDescription = - stringResource(id = R.string.course_accessibility_section_completed) - - Icon( - painter = completedIconPainter, - contentDescription = completedIconDescription, - tint = completedIconColor - ) - Spacer(modifier = Modifier.width(16.dp)) + if (downloadedState == DownloadedState.DOWNLOADED || downloadedState == DownloadedState.NOT_DOWNLOADED) { + val downloadIconPainter = + if (downloadedState == DownloadedState.DOWNLOADED) { + rememberVectorPainter(Icons.Default.CloudDone) + } else { + painterResource(id = R.drawable.course_ic_start_download) + } + val downloadIconDescription = + if (downloadedState == DownloadedState.DOWNLOADED) { + stringResource(id = R.string.course_accessibility_remove_course_section) + } else { + stringResource(id = R.string.course_accessibility_download_course_section) + } + val downloadIconTint = + if (downloadedState == DownloadedState.DOWNLOADED) { + MaterialTheme.appColors.successGreen + } else { + MaterialTheme.appColors.textAccent + } + IconButton(modifier = iconModifier, + onClick = { onDownloadClick() }) { + Icon( + painter = downloadIconPainter, + contentDescription = downloadIconDescription, + tint = downloadIconTint + ) + } + } else if (downloadedState != null) { + Box(contentAlignment = Alignment.Center) { + if (downloadedState == DownloadedState.DOWNLOADING) { + CircularProgressIndicator( + modifier = Modifier.size(28.dp), + backgroundColor = Color.LightGray, + strokeWidth = 2.dp, + color = MaterialTheme.appColors.primary + ) + } else if (downloadedState == DownloadedState.WAITING) { + Icon( + painter = painterResource(id = R.drawable.course_download_waiting), + contentDescription = stringResource(id = R.string.course_accessibility_stop_downloading_course_section), + tint = MaterialTheme.appColors.error + ) + } + IconButton( + modifier = iconModifier.padding(2.dp), + onClick = { onDownloadClick() }) { + Icon( + imageVector = Icons.Filled.Close, + contentDescription = stringResource(id = R.string.course_accessibility_stop_downloading_course_section), + tint = MaterialTheme.appColors.error + ) + } + } } - Text( - modifier = Modifier.weight(1f), - text = block.displayName, - style = MaterialTheme.appTypography.titleSmall, - color = MaterialTheme.appColors.textPrimary, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Spacer(modifier = Modifier.width(16.dp)) - CardArrow(degrees = arrowDegrees) } } } @Composable fun CourseSubSectionItem( - modifier: Modifier, + modifier: Modifier = Modifier, block: Block, - downloadedState: DownloadedState?, - downloadsCount: Int, onClick: (Block) -> Unit, - onDownloadClick: (Block) -> Unit, ) { + val context = LocalContext.current val icon = - if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource( - coreR.drawable.ic_core_chapter_icon - ) + if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource(coreR.drawable.ic_core_chapter_icon) val iconColor = - if (block.isCompleted()) MaterialTheme.appColors.primary else MaterialTheme.appColors.onSurface - - val iconModifier = Modifier.size(24.dp) - - Column(Modifier - .clickable { onClick(block) } - .background(if (block.isCompleted()) MaterialTheme.appColors.surface else Color.Transparent) + if (block.isCompleted()) MaterialTheme.appColors.successGreen else MaterialTheme.appColors.onSurface + val due by rememberSaveable { + mutableStateOf(block.due?.let { TimeUtils.getAssignmentFormattedDate(context, it) }) + } + val isAssignmentEnable = !block.isCompleted() && block.assignmentProgress != null && !due.isNullOrEmpty() + Column( + modifier = modifier + .fillMaxWidth() + .clickable { onClick(block) } + .padding(horizontal = 16.dp, vertical = 12.dp) ) { Row( - modifier - .fillMaxWidth() - .height(60.dp) - .padding(vertical = 16.dp) - .padding(start = 20.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { @@ -656,7 +765,7 @@ fun CourseSubSectionItem( contentDescription = null, tint = iconColor ) - Spacer(modifier = Modifier.width(16.dp)) + Spacer(modifier = Modifier.width(4.dp)) Text( modifier = Modifier.weight(1f), text = block.displayName, @@ -666,63 +775,31 @@ fun CourseSubSectionItem( maxLines = 1 ) Spacer(modifier = Modifier.width(16.dp)) - Row( - modifier = Modifier.fillMaxHeight(), - horizontalArrangement = Arrangement.spacedBy(if (downloadsCount > 0) 8.dp else 24.dp), - verticalAlignment = Alignment.CenterVertically - ) { - if (downloadedState == DownloadedState.DOWNLOADED || downloadedState == DownloadedState.NOT_DOWNLOADED) { - val downloadIconPainter = if (downloadedState == DownloadedState.DOWNLOADED) { - painterResource(id = R.drawable.course_ic_remove_download) - } else { - painterResource(id = R.drawable.course_ic_start_download) - } - val downloadIconDescription = - if (downloadedState == DownloadedState.DOWNLOADED) { - stringResource(id = R.string.course_accessibility_remove_course_section) - } else { - stringResource(id = R.string.course_accessibility_download_course_section) - } - IconButton(modifier = iconModifier, - onClick = { onDownloadClick(block) }) { - Icon( - painter = downloadIconPainter, - contentDescription = downloadIconDescription, - tint = MaterialTheme.appColors.textPrimary - ) - } - } else if (downloadedState != null) { - Box(contentAlignment = Alignment.Center) { - if (downloadedState == DownloadedState.DOWNLOADING || downloadedState == DownloadedState.WAITING) { - CircularProgressIndicator( - modifier = Modifier.size(28.dp), - backgroundColor = Color.LightGray, - strokeWidth = 2.dp, - color = MaterialTheme.appColors.primary - ) - } - IconButton( - modifier = iconModifier.padding(2.dp), - onClick = { onDownloadClick(block) }) { - Text( - modifier = Modifier - .padding(bottom = 4.dp), - text = "i", - style = MaterialTheme.appTypography.titleMedium, - color = MaterialTheme.appColors.primary - ) - } - } - } - if (downloadsCount > 0) { - Text( - text = downloadsCount.toString(), - style = MaterialTheme.appTypography.titleSmall, - color = MaterialTheme.appColors.textPrimary - ) - } + if (isAssignmentEnable) { + Icon( + imageVector = Icons.Filled.ChevronRight, + tint = MaterialTheme.appColors.onSurface, + contentDescription = null + ) } } + + if (isAssignmentEnable) { + val assignmentString = + stringResource( + R.string.course_subsection_assignment_info, + block.assignmentProgress?.assignmentType ?: "", + due ?: "", + block.assignmentProgress?.numPointsEarned?.toInt() ?: 0, + block.assignmentProgress?.numPointsPossible?.toInt() ?: 0 + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = assignmentString, + style = MaterialTheme.appTypography.bodySmall, + color = MaterialTheme.appColors.textPrimary + ) + } } } @@ -1146,7 +1223,7 @@ private fun NavigationUnitsButtonsWithNextPreview() { @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -private fun CourseChapterItemPreview() { +private fun CourseSectionCardPreview() { OpenEdXTheme { Surface(color = MaterialTheme.appColors.background) { CourseSectionCard( @@ -1246,5 +1323,7 @@ private val mockChapterBlock = Block( descendants = emptyList(), descendantsType = BlockType.CHAPTER, completion = 0.0, - containsGatedContent = false + containsGatedContent = false, + assignmentProgress = AssignmentProgress("", 1f, 2f), + due = Date() ) diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt index 6e8f19610..7beb0f91d 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt @@ -1,7 +1,6 @@ package org.openedx.course.presentation.ui import android.content.res.Configuration -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween @@ -19,7 +18,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.AlertDialog @@ -59,10 +57,12 @@ import androidx.fragment.app.FragmentManager import org.openedx.core.AppDataConstants import org.openedx.core.BlockType import org.openedx.core.UIMessage +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.Progress import org.openedx.core.domain.model.VideoSettings import org.openedx.core.extension.toFileSize import org.openedx.core.module.download.DownloadModelsSize @@ -98,7 +98,6 @@ fun CourseVideosScreen( uiState = uiState, uiMessage = uiMessage, courseTitle = viewModel.courseTitle, - isCourseNestedListEnabled = viewModel.isCourseNestedListEnabled, videoSettings = videoSettings, onItemClick = { block -> viewModel.courseRouter.navigateToCourseSubsections( @@ -125,20 +124,12 @@ fun CourseVideosScreen( ) } }, - onDownloadClick = { - if (viewModel.isBlockDownloading(it.id)) { - viewModel.courseRouter.navigateToDownloadQueue( - fm = fragmentManager, - viewModel.getDownloadableChildren(it.id) - ?: arrayListOf() - ) - } else if (viewModel.isBlockDownloaded(it.id)) { - viewModel.removeDownloadModels(it.id) - } else { - viewModel.saveDownloadModels( - FileUtil(context).getExternalAppDir().path, it.id - ) - } + onDownloadClick = { blocksIds -> + viewModel.downloadBlocks( + blocksIds = blocksIds, + fragmentManager = fragmentManager, + context = context + ) }, onDownloadAllClick = { isAllBlocksDownloadedOrDownloading -> viewModel.logBulkDownloadToggleEvent(!isAllBlocksDownloadedOrDownloading) @@ -174,12 +165,11 @@ private fun CourseVideosUI( uiState: CourseVideosUIState, uiMessage: UIMessage?, courseTitle: String, - isCourseNestedListEnabled: Boolean, videoSettings: VideoSettings, onItemClick: (Block) -> Unit, onExpandClick: (Block) -> Unit, onSubSectionClick: (Block) -> Unit, - onDownloadClick: (Block) -> Unit, + onDownloadClick: (blocksIds: List) -> Unit, onDownloadAllClick: (Boolean) -> Unit, onDownloadQueueClick: () -> Unit, onVideoDownloadQualityClick: () -> Unit @@ -294,88 +284,26 @@ private fun CourseVideosUI( } } - if (isCourseNestedListEnabled) { - uiState.courseStructure.blockData.forEach { section -> - val courseSubSections = uiState.courseSubSections[section.id] - val courseSectionsState = uiState.courseSectionsState[section.id] - - item { - Column { - CourseExpandableChapterCard( - modifier = listPadding, - block = section, - onItemClick = onExpandClick, - arrowDegrees = if (courseSectionsState == true) -90f else 90f - ) - Divider() - } - } - - courseSubSections?.forEach { subSectionBlock -> - item { - Column { - AnimatedVisibility( - visible = courseSectionsState == true - ) { - Column { - val downloadsCount = - uiState.subSectionsDownloadsCount[subSectionBlock.id] - ?: 0 - - CourseSubSectionItem( - modifier = listPadding, - block = subSectionBlock, - downloadedState = uiState.downloadedState[subSectionBlock.id], - downloadsCount = downloadsCount, - onClick = onSubSectionClick, - onDownloadClick = { block -> - if (uiState.downloadedState[block.id]?.isDownloaded == true) { - deleteDownloadBlock = - block - - } else { - onDownloadClick(block) - } - } - ) - Divider() - } - } - } - } - } - } - return@LazyColumn + item { + Spacer(modifier = Modifier.height(12.dp)) } + uiState.courseStructure.blockData.forEach { section -> + val courseSubSections = + uiState.courseSubSections[section.id] + val courseSectionsState = + uiState.courseSectionsState[section.id] - items(uiState.courseStructure.blockData) { block -> - Column(listPadding) { - if (block.type == BlockType.CHAPTER) { - Text( - modifier = Modifier.padding( - top = 36.dp, - bottom = 8.dp - ), - text = block.displayName, - style = MaterialTheme.appTypography.titleMedium, - color = MaterialTheme.appColors.textPrimaryVariant - ) - } else { - CourseSectionCard( - block = block, - downloadedState = uiState.downloadedState[block.id], - onItemClick = onItemClick, - onDownloadClick = { block -> - if (uiState.downloadedState[block.id]?.isDownloaded == true) { - deleteDownloadBlock = block - - } else { - onDownloadClick(block) - } - } - ) - Divider() - } + item { + CourseSection( + modifier = listPadding.padding(vertical = 4.dp), + block = section, + onItemClick = onExpandClick, + courseSectionsState = courseSectionsState, + courseSubSections = courseSubSections, + downloadedStateMap = uiState.downloadedState, + onSubSectionClick = onSubSectionClick, + onDownloadClick = onDownloadClick + ) } } } @@ -497,7 +425,7 @@ private fun CourseVideosUI( TextButton( onClick = { deleteDownloadBlock?.let { block -> - onDownloadClick(block) + onDownloadClick(listOf(block.id)) } deleteDownloadBlock = null } @@ -708,7 +636,6 @@ private fun CourseVideosScreenPreview() { ) ), courseTitle = "", - isCourseNestedListEnabled = false, onItemClick = { }, onExpandClick = { }, onSubSectionClick = { }, @@ -733,7 +660,6 @@ private fun CourseVideosScreenEmptyPreview() { "This course does not include any videos." ), courseTitle = "", - isCourseNestedListEnabled = false, onItemClick = { }, onExpandClick = { }, onSubSectionClick = { }, @@ -769,7 +695,6 @@ private fun CourseVideosScreenTabletPreview() { ) ), courseTitle = "", - isCourseNestedListEnabled = false, onItemClick = { }, onExpandClick = { }, onSubSectionClick = { }, @@ -782,6 +707,11 @@ private fun CourseVideosScreenTabletPreview() { } } +private val mockAssignmentProgress = AssignmentProgress( + assignmentType = "Home", + numPointsEarned = 1f, + numPointsPossible = 3f +) private val mockChapterBlock = Block( id = "id", @@ -798,7 +728,9 @@ private val mockChapterBlock = Block( descendants = emptyList(), descendantsType = BlockType.CHAPTER, completion = 0.0, - containsGatedContent = false + containsGatedContent = false, + assignmentProgress = mockAssignmentProgress, + due = Date() ) private val mockSequentialBlock = Block( @@ -816,7 +748,9 @@ private val mockSequentialBlock = Block( descendants = emptyList(), descendantsType = BlockType.SEQUENTIAL, completion = 0.0, - containsGatedContent = false + containsGatedContent = false, + assignmentProgress = mockAssignmentProgress, + due = Date() ) private val mockCourseStructure = CourseStructure( @@ -840,5 +774,6 @@ private val mockCourseStructure = CourseStructure( ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = Progress(1, 3) ) diff --git a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt index 61fc896bf..af4d839e7 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt @@ -37,7 +37,7 @@ class CourseUnitContainerViewModel( private val blocks = ArrayList() - val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled + val isCourseExpandableSectionsEnabled get() = config.getCourseUIConfig().isCourseDropdownNavigationEnabled val isCourseUnitProgressEnabled get() = config.getCourseUIConfig().isCourseUnitProgressEnabled diff --git a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt index 2cf3d8797..49f3b6120 100644 --- a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt @@ -1,5 +1,7 @@ package org.openedx.course.presentation.videos +import android.content.Context +import androidx.fragment.app.FragmentManager import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -25,6 +27,7 @@ import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseStructureUpdated import org.openedx.core.system.notifier.VideoNotifier import org.openedx.core.system.notifier.VideoQualityChanged +import org.openedx.core.utils.FileUtil import org.openedx.course.R import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics @@ -53,7 +56,7 @@ class CourseVideoViewModel( coreAnalytics ) { - val isCourseNestedListEnabled get() = config.getCourseUIConfig().isCourseNestedListEnabled + val isCourseNestedListEnabled get() = config.getCourseUIConfig().isCourseDropdownNavigationEnabled private val _uiState = MutableStateFlow(CourseVideosUIState.Loading) val uiState: StateFlow @@ -199,15 +202,10 @@ class CourseVideoViewModel( resultBlocks.add(block) block.descendants.forEach { descendant -> blocks.find { it.id == descendant }?.let { - if (isCourseNestedListEnabled) { - courseSubSections.getOrPut(block.id) { mutableListOf() } - .add(it) - courseSubSectionUnit[it.id] = it.getFirstDescendantBlock(blocks) - subSectionsDownloadsCount[it.id] = it.getDownloadsCount(blocks) - - } else { - resultBlocks.add(it) - } + courseSubSections.getOrPut(block.id) { mutableListOf() } + .add(it) + courseSubSectionUnit[it.id] = it.getFirstDescendantBlock(blocks) + subSectionsDownloadsCount[it.id] = it.getDownloadsCount(blocks) addDownloadableChildrenForSequentialBlock(it) } } @@ -215,4 +213,21 @@ class CourseVideoViewModel( } return resultBlocks.toList() } + + fun downloadBlocks(blocksIds: List, fragmentManager: FragmentManager, context: Context) { + blocksIds.forEach { blockId -> + if (isBlockDownloading(blockId)) { + courseRouter.navigateToDownloadQueue( + fm = fragmentManager, + getDownloadableChildren(blockId) ?: arrayListOf() + ) + } else if (isBlockDownloaded(blockId)) { + removeDownloadModels(blockId) + } else { + saveDownloadModels( + FileUtil(context).getExternalAppDir().path, blockId + ) + } + } + } } diff --git a/course/src/main/res/drawable/course_download_waiting.png b/course/src/main/res/drawable/course_download_waiting.png new file mode 100644 index 0000000000000000000000000000000000000000..c4a04af69630a5f614eb1b71780d4554038f2043 GIT binary patch literal 1945 zcmV;K2WI$*P)upfI!Tjv0M#aRK#3J5CzRsgI3x&nt4Bw0b+*J4iG66mAl9k}N} z9vWNI`;8?lO#E%-@Z&4#3UAI>-VUe&D4k&MJ`6h!JC9`M>?@`A9{k+unVwTj9$V`0l|Q1C z`kDEViI3#Dx3>C=LMa409S$3lFSIX%z>L8%)9K8#D<3^m8OI?{DRX_uBMXGcsI!4T zL<};)vL0WutNpo{m0?{^a~G#Sg+-0dp?&R*~+OYjcs|pZzq`i3lHb&A!;hc zT_N1C|7o~O1*33+1!!2(o2RG4rYXaBQ;1^0=|8%zwkZ#UV`c5fwNW_1f~C;2#pbmdBQ5x&2eiV^&Y3>`wfJwC(MdXKu&9 zRilRNefS!bvgw0U_0PPXeC^~YMg`7@US&3YaKQct@9_QE=ylq2iCH$rZ}*nEeSfRD zLj?hKxvpwq7Geon+P(txz5mfW#8@aNIM2gqKsewD1skof^5+k>T5oL6_x~Oquv^~0 zodh_v>}yS#;V5pYjQ~Pdpv_OxeO>Q3!p)H7?!he=}T21Uva*n6dcK03_ZWIDz)J?E3G%QF+frk`~~ZA*3o zGw(Y4!A${uGp&vYirPZ7ZkD<-Zu)AJnkz)RIJb1B0?5=il|IH0nfEYR|1V|vy)abZ zIj-8tvvGb4*!Eyx5%Y>87nhuA9=IDex-7&BVIbN#O@m@WE`r4y#rI_*RtWT87}%){ ze0*d5mjiU;&yT}4Eh*6VDl@6o26RY}m}$)c8kp#CWeZ&eVC&8n>ktX&!r z!Q^;gx3H9??yV9;;{V;Ad$}x~Sb;s76&fTTm*v=_6^9sFuAC)hW_h5ArcIb;Dy)w` zVvz}r3`MGys|;{Se9CG&-ngJ6oAISajT$v-tO;13$d&UDK3I_ELr)p_Gps9@fWyqi zchqor=FkFLrwI0UeDeQdSh0!C4kEB9ubZ|)D`G}fq5qehKYgIPrlF0o0wp-=s~si@@){T6l%lV?vvurTUOEJV9X&C4Qi z7tiW6yQ~P@poVjaOaoTj6OrpU^dXA^8{ph4f?0zM5oMFl^h`cp(h9>EhNE;OUK>$z z^6NH|E{{e^y|q;)1)kEX!|W!ZfmqD&d(4naM`TB1m0h6XPBr>>=9Y-qxKbw4y+$4aP{Ou*HO%#GF_G-__}+<`mGv zf>5uPB`l^W%xoO|B6KRex7BPdEKs{_&gf7^2y~4sfXnu}x}E0_FokE&7d~|qpDaTZ zTN3EAtN0LOxK96b5e&yCL{S7X%Pfj*iHH^toxuy=^Ey0dCYZh(XXZE?P35rBWr>$e z24`tbC}TpDZq|A-#Tp?-T4c0mDV2CrR(rqQZ4Ib`z@CLIgzWce;P~@KWX;n>Q_9)M z8oQ0YBKkI#G|)E+lyMD12z}n%;I14>NB6f{Rz?uN@*oWKvZ;N)208%#+<7X09{Qp; z^+i`h^gj&WNU!c-8Rp$eauX~o0{wW$kku>7MsO2tBvH!UJ2R)WeE05z<&yqcFx6kf zsjq_>UWTTnoGbm()V*w0g$G86E+^(ZZmpATpl9;)KmdZsPaShRx(_`n7^U1$w;(F6 zXG)(;>}B9@YD(X5Q`PF7G8j(b1cUdFN&E;fxXz{z=Uh|z?9MT3TcyZ_g%j-lFRdeJ zDU(-J&7iFALTP?kX;lTSi7XyW0(o?{lV4}UP~HBz^QtRo?}?sEd - - - - - - + diff --git a/course/src/main/res/values/strings.xml b/course/src/main/res/values/strings.xml index 3d6e13094..2fcb1d950 100644 --- a/course/src/main/res/values/strings.xml +++ b/course/src/main/res/values/strings.xml @@ -62,5 +62,15 @@ Turning off the switch will stop downloading and delete all downloaded videos for \"%s\"? Are you sure you want to delete all video(s) for \"%s\"? Are you sure you want to delete video(s) for \"%s\"? + %1$s - %2$s - %3$d / %4$d + + + %1$s of %2$s assignments complete + %1$s of %2$s assignment complete + %1$s of %2$s assignments complete + %1$s of %2$s assignments complete + %1$s of %2$s assignments complete + %1$s of %2$s assignments complete + diff --git a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt index c20bb07be..938d850d2 100644 --- a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt @@ -108,7 +108,8 @@ class CourseContainerViewModelTest { ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = null ) private val courseStructureModel = CourseStructureModel( @@ -125,7 +126,8 @@ class CourseContainerViewModelTest { coursewareAccess = null, media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = null ) @Before @@ -168,12 +170,12 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns true - coEvery { interactor.getCourseStructure(any()) } throws UnknownHostException() + coEvery { interactor.getCourseStructure(any(), any()) } throws UnknownHostException() every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() - coVerify(exactly = 1) { interactor.getCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any(), any()) } verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } val message = viewModel.errorMessage.value @@ -202,12 +204,12 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns true - coEvery { interactor.getCourseStructure(any()) } throws Exception() + coEvery { interactor.getCourseStructure(any(), any()) } throws Exception() every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() - coVerify(exactly = 1) { interactor.getCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any(), any()) } verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } val message = viewModel.errorMessage.value @@ -236,12 +238,12 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns true - coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructure(any(), any()) } returns courseStructure every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() - coVerify(exactly = 1) { interactor.getCourseStructure(any()) } + coVerify(exactly = 1) { interactor.getCourseStructure(any(), any()) } verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } assert(viewModel.errorMessage.value == null) @@ -269,7 +271,7 @@ class CourseContainerViewModelTest { courseRouter ) every { networkConnection.isOnline() } returns false - coEvery { interactor.getCourseStructure(any()) } returns courseStructure + coEvery { interactor.getCourseStructure(any(), any()) } returns courseStructure every { analytics.logEvent(any(), any()) } returns Unit coEvery { courseApi.getCourseStructure(any(), any(), any(), any()) diff --git a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt index 5e2ed50a4..11ffb4932 100644 --- a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt @@ -136,6 +136,7 @@ class CourseDatesViewModelTest { media = null, certificate = null, isSelfPaced = true, + progress = null ) @Before 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 941fbfdac..aad650b28 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 @@ -33,6 +33,7 @@ import org.openedx.core.UIMessage import org.openedx.core.config.Config import org.openedx.core.data.model.DateType import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseComponentStatus @@ -84,6 +85,12 @@ class CourseOutlineViewModelTest { private val somethingWrong = "Something went wrong" private val cantDownload = "You can download content only from Wi-fi" + private val assignmentProgress = AssignmentProgress( + assignmentType = "Homework", + numPointsEarned = 1f, + numPointsPossible = 3f + ) + private val blocks = listOf( Block( id = "id", @@ -99,7 +106,9 @@ class CourseOutlineViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("1", "id1"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id1", @@ -115,7 +124,9 @@ class CourseOutlineViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("id2"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id2", @@ -131,7 +142,9 @@ class CourseOutlineViewModelTest { blockCounts = BlockCounts(0), descendants = emptyList(), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ) ) @@ -156,7 +169,8 @@ class CourseOutlineViewModelTest { ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = null ) private val dateBlock = CourseDateBlock( @@ -303,7 +317,7 @@ class CourseOutlineViewModelTest { ) } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -351,7 +365,7 @@ class CourseOutlineViewModelTest { ) } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -398,7 +412,7 @@ class CourseOutlineViewModelTest { ) } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -482,7 +496,7 @@ class CourseOutlineViewModelTest { coEvery { workerController.saveModels(any()) } returns Unit coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false val viewModel = CourseOutlineViewModel( "", @@ -525,7 +539,7 @@ class CourseOutlineViewModelTest { every { networkConnection.isOnline() } returns true coEvery { workerController.saveModels(any()) } returns Unit coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false every { coreAnalytics.logEvent(any(), any()) } returns Unit val viewModel = CourseOutlineViewModel( @@ -562,7 +576,7 @@ class CourseOutlineViewModelTest { every { networkConnection.isOnline() } returns false coEvery { workerController.saveModels(any()) } returns Unit coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false val viewModel = CourseOutlineViewModel( "", diff --git a/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt index 0a398371b..01c685c48 100644 --- a/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt @@ -27,6 +27,7 @@ import org.openedx.core.BlockType import org.openedx.core.R import org.openedx.core.UIMessage import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseStructure @@ -69,6 +70,11 @@ class CourseSectionViewModelTest { private val somethingWrong = "Something went wrong" private val cantDownload = "You can download content only from Wi-fi" + private val assignmentProgress = AssignmentProgress( + assignmentType = "Homework", + numPointsEarned = 1f, + numPointsPossible = 3f + ) private val blocks = listOf( Block( @@ -85,7 +91,9 @@ class CourseSectionViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("1", "id1"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id1", @@ -101,7 +109,9 @@ class CourseSectionViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("id2"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id2", @@ -117,7 +127,9 @@ class CourseSectionViewModelTest { blockCounts = BlockCounts(0), descendants = emptyList(), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ) ) @@ -142,7 +154,8 @@ class CourseSectionViewModelTest { ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = null ) private val downloadModel = DownloadModel( diff --git a/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt index 1e5354a95..166d7751e 100644 --- a/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt @@ -20,6 +20,7 @@ import org.junit.Test import org.junit.rules.TestRule import org.openedx.core.BlockType import org.openedx.core.config.Config +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseStructure @@ -44,6 +45,12 @@ class CourseUnitContainerViewModelTest { private val notifier = mockk() private val analytics = mockk() + private val assignmentProgress = AssignmentProgress( + assignmentType = "Homework", + numPointsEarned = 1f, + numPointsPossible = 3f + ) + private val blocks = listOf( Block( id = "id", @@ -59,7 +66,9 @@ class CourseUnitContainerViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("id2", "id1"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id1", @@ -75,7 +84,9 @@ class CourseUnitContainerViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("id2", "id"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id2", @@ -91,7 +102,9 @@ class CourseUnitContainerViewModelTest { blockCounts = BlockCounts(0), descendants = emptyList(), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id3", @@ -107,7 +120,9 @@ class CourseUnitContainerViewModelTest { blockCounts = BlockCounts(0), descendants = emptyList(), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ) ) @@ -133,7 +148,8 @@ class CourseUnitContainerViewModelTest { ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = null ) @Before diff --git a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt index a15de0583..9bb8d0f5f 100644 --- a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt @@ -32,6 +32,7 @@ import org.openedx.core.BlockType import org.openedx.core.UIMessage import org.openedx.core.config.Config import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseStructure @@ -78,6 +79,12 @@ class CourseVideoViewModelTest { private val cantDownload = "You can download content only from Wi-fi" + private val assignmentProgress = AssignmentProgress( + assignmentType = "Homework", + numPointsEarned = 1f, + numPointsPossible = 3f + ) + private val blocks = listOf( Block( id = "id", @@ -93,7 +100,9 @@ class CourseVideoViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("1", "id1"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id1", @@ -109,7 +118,9 @@ class CourseVideoViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("id2"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id2", @@ -125,7 +136,9 @@ class CourseVideoViewModelTest { blockCounts = BlockCounts(0), descendants = emptyList(), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ) ) @@ -150,7 +163,8 @@ class CourseVideoViewModelTest { ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = null ) private val downloadModelEntity = @@ -183,7 +197,7 @@ class CourseVideoViewModelTest { @Test fun `getVideos empty list`() = runTest { - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure.copy(blockData = emptyList()) every { downloadDao.readAllData() } returns flow { emit(emptyList()) } @@ -215,7 +229,7 @@ class CourseVideoViewModelTest { @Test fun `getVideos success`() = runTest { - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure every { downloadDao.readAllData() } returns flow { emit(emptyList()) } every { preferencesManager.videoSettings } returns VideoSettings.default @@ -248,7 +262,7 @@ class CourseVideoViewModelTest { @Test fun `updateVideos success`() = runTest { - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { courseNotifier.notifier } returns flow { emit(CourseStructureUpdated("")) @@ -291,7 +305,7 @@ class CourseVideoViewModelTest { @Test fun `setIsUpdating success`() = runTest { - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } @@ -300,7 +314,7 @@ class CourseVideoViewModelTest { @Test fun `saveDownloadModels test`() = runTest(UnconfinedTestDispatcher()) { - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default val viewModel = CourseVideoViewModel( "", @@ -337,7 +351,7 @@ class CourseVideoViewModelTest { @Test fun `saveDownloadModels only wifi download, with connection`() = runTest(UnconfinedTestDispatcher()) { - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default val viewModel = CourseVideoViewModel( "", @@ -378,7 +392,7 @@ class CourseVideoViewModelTest { @Test fun `saveDownloadModels only wifi download, without connection`() = runTest(UnconfinedTestDispatcher()) { - every { config.getCourseUIConfig().isCourseNestedListEnabled } returns false + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false every { preferencesManager.videoSettings } returns VideoSettings.default val viewModel = CourseVideoViewModel( "", diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt index c4ea029b9..74515e0c1 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt @@ -55,6 +55,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -564,7 +565,11 @@ private fun PrimaryCourseCard( }, painter = rememberVectorPainter(Icons.Default.Warning), title = title, - info = stringResource(R.string.dashboard_past_due_assignment, pastAssignments.size) + info = pluralStringResource( + R.plurals.dashboard_past_due_assignment, + pastAssignments.size, + pastAssignments.size + ) ) } val futureAssignments = primaryCourse.courseAssignments?.futureAssignments @@ -583,9 +588,9 @@ private fun PrimaryCourseCard( painter = painterResource(id = CoreR.drawable.ic_core_chapter_icon), title = title, info = stringResource( - R.string.dashboard_assignment_due_in_days, + R.string.dashboard_assignment_due, nearestAssignment.assignmentType ?: "", - TimeUtils.getCourseFormattedDate(context, nearestAssignment.date) + TimeUtils.getAssignmentFormattedDate(context, nearestAssignment.date) ) ) } @@ -769,7 +774,7 @@ private fun NoCoursesInfo( private val mockCourseDateBlock = CourseDateBlock( title = "Homework 1: ABCD", description = "After this date, course content will be archived", - date = TimeUtils.iso8601ToDate("2023-10-20T15:08:07Z")!!, + date = TimeUtils.iso8601ToDate("2024-05-31T15:08:07Z")!!, assignmentType = "Homework" ) private val mockCourseAssignments = diff --git a/dashboard/src/main/res/values/strings.xml b/dashboard/src/main/res/values/strings.xml index 4ca0c4fce..23a33fb50 100644 --- a/dashboard/src/main/res/values/strings.xml +++ b/dashboard/src/main/res/values/strings.xml @@ -9,10 +9,9 @@ Course %1$s Start Course Resume Course - %1$d Past Due Assignments View All Courses (%1$d) View All - %1$s Due in %2$s + %1$s %2$s All In Progress Completed @@ -22,4 +21,13 @@ You are not currently enrolled in any courses, would you like to explore the course catalog? Find a Course No %1$s Courses + + + %1$d Past Due Assignments + %1$d Past Due Assignment + %1$d Past Due Assignments + %1$d Past Due Assignments + %1$d Past Due Assignments + %1$d Past Due Assignments + diff --git a/default_config/dev/config.yaml b/default_config/dev/config.yaml index 8c08df7f6..8b1dc8f07 100644 --- a/default_config/dev/config.yaml +++ b/default_config/dev/config.yaml @@ -82,4 +82,3 @@ SOCIAL_AUTH_ENABLED: false UI_COMPONENTS: COURSE_NESTED_LIST_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false - diff --git a/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt b/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt index b74cc6644..9fc56f6af 100644 --- a/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt +++ b/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt @@ -26,6 +26,7 @@ import org.junit.rules.TestRule import org.openedx.core.BlockType import org.openedx.core.R import org.openedx.core.UIMessage +import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts import org.openedx.core.domain.model.CourseStructure @@ -56,6 +57,12 @@ class DiscussionTopicsViewModelTest { private val noInternet = "Slow or no internet connection" private val somethingWrong = "Something went wrong" + private val assignmentProgress = AssignmentProgress( + assignmentType = "Homework", + numPointsEarned = 1f, + numPointsPossible = 3f + ) + private val blocks = listOf( Block( id = "id", @@ -71,7 +78,9 @@ class DiscussionTopicsViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("1", "id1"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id1", @@ -87,7 +96,9 @@ class DiscussionTopicsViewModelTest { blockCounts = BlockCounts(0), descendants = listOf("id2"), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ), Block( id = "id2", @@ -103,7 +114,9 @@ class DiscussionTopicsViewModelTest { blockCounts = BlockCounts(0), descendants = emptyList(), descendantsType = BlockType.HTML, - completion = 0.0 + completion = 0.0, + assignmentProgress = assignmentProgress, + due = Date() ) ) private val courseStructure = CourseStructure( @@ -127,7 +140,8 @@ class DiscussionTopicsViewModelTest { ), media = null, certificate = null, - isSelfPaced = false + isSelfPaced = false, + progress = null ) @Before diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt index 419172232..f94064d30 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt @@ -518,7 +518,7 @@ private fun AppVersionItemAppToDate(versionName: String) { ), painter = painterResource(id = R.drawable.core_ic_check), contentDescription = null, - tint = MaterialTheme.appColors.accessGreen + tint = MaterialTheme.appColors.successGreen ) Text( modifier = Modifier.testTag("txt_up_to_date"), From 09b422af27e1d1fab19241153656d0c12f4659a8 Mon Sep 17 00:00:00 2001 From: Omer Habib <30689349+omerhabib26@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:01:10 +0500 Subject: [PATCH 11/38] fix: enable Programs view for new dashboard navigation (#328) - Update/optimise ProgramFragment - enable ProgramFragment for both dashboards(list/gallery) - hide dropdown on Learn Tab if programs not available fix: LEARNER-10035 --- .../main/java/org/openedx/app/AppRouter.kt | 43 +++++++++++------- .../main/java/org/openedx/app/MainFragment.kt | 10 ++--- .../java/org/openedx/app/MainViewModel.kt | 4 +- .../java/org/openedx/DashboardNavigator.kt | 4 +- .../presentation/DashboardListFragment.kt | 44 ++----------------- .../dashboard/presentation/DashboardRouter.kt | 2 +- .../learn/presentation/LearnFragment.kt | 24 +++++----- .../learn/presentation/LearnViewModel.kt | 8 +++- dashboard/src/main/res/values-uk/strings.xml | 2 - dashboard/src/main/res/values/strings.xml | 2 - .../presentation/program/ProgramFragment.kt | 38 +++++++++------- 11 files changed, 79 insertions(+), 102 deletions(-) diff --git a/app/src/main/java/org/openedx/app/AppRouter.kt b/app/src/main/java/org/openedx/app/AppRouter.kt index 17b47d11d..fe4394cde 100644 --- a/app/src/main/java/org/openedx/app/AppRouter.kt +++ b/app/src/main/java/org/openedx/app/AppRouter.kt @@ -128,8 +128,8 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di replaceFragmentWithBackStack(fm, AllEnrolledCoursesFragment()) } - override fun getProgramFragmentInstance(): Fragment { - return ProgramFragment(myPrograms = true, isNestedFragment = true) + override fun getProgramFragment(): Fragment { + return ProgramFragment.newInstance(isNestedFragment = true) } override fun navigateToCourseInfo( @@ -144,7 +144,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di fm: FragmentManager, courseId: String, courseTitle: String, - enrollmentMode: String + enrollmentMode: String, ) { replaceFragmentWithBackStack( fm, @@ -161,21 +161,30 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseTitle: String, enrollmentMode: String, openTab: String, - resumeBlockId: String + resumeBlockId: String, ) { replaceFragmentWithBackStack( fm, - CourseContainerFragment.newInstance(courseId, courseTitle, enrollmentMode, openTab, resumeBlockId) + CourseContainerFragment.newInstance( + courseId, + courseTitle, + enrollmentMode, + openTab, + resumeBlockId + ) ) } override fun navigateToEnrolledProgramInfo(fm: FragmentManager, pathId: String) { - replaceFragmentWithBackStack(fm, ProgramFragment.newInstance(pathId)) + replaceFragmentWithBackStack( + fm, + ProgramFragment.newInstance(pathId = pathId, isNestedFragment = false) + ) } override fun navigateToNoAccess( fm: FragmentManager, - title: String + title: String, ) { replaceFragment(fm, NoAccessCourseContainerFragment.newInstance(title)) } @@ -189,7 +198,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di subSectionId: String, unitId: String, componentId: String, - mode: CourseViewMode + mode: CourseViewMode, ) { replaceFragmentWithBackStack( fm, @@ -208,7 +217,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseId: String, unitId: String, componentId: String, - mode: CourseViewMode + mode: CourseViewMode, ) { replaceFragmentWithBackStack( fm, @@ -226,7 +235,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseId: String, unitId: String, componentId: String, - mode: CourseViewMode + mode: CourseViewMode, ) { replaceFragment( fm, @@ -246,7 +255,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di videoTime: Long, blockId: String, courseId: String, - isPlaying: Boolean + isPlaying: Boolean, ) { replaceFragmentWithBackStack( fm, @@ -260,7 +269,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di videoTime: Long, blockId: String, courseId: String, - isPlaying: Boolean + isPlaying: Boolean, ) { replaceFragmentWithBackStack( fm, @@ -278,7 +287,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di fm: FragmentManager, courseId: String, title: String, - type: HandoutsType + type: HandoutsType, ) { replaceFragmentWithBackStack( fm, @@ -294,7 +303,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseId: String, topicId: String, title: String, - viewType: FragmentViewType + viewType: FragmentViewType, ) { replaceFragmentWithBackStack( fm, @@ -312,7 +321,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di override fun navigateToDiscussionResponses( fm: FragmentManager, comment: DiscussionComment, - isClosed: Boolean + isClosed: Boolean, ) { replaceFragmentWithBackStack( fm, @@ -340,7 +349,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di override fun navigateToAnothersProfile( fm: FragmentManager, - username: String + username: String, ) { replaceFragmentWithBackStack( fm, @@ -410,7 +419,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di private fun replaceFragment( fm: FragmentManager, fragment: Fragment, - transaction: Int = FragmentTransaction.TRANSIT_NONE + transaction: Int = FragmentTransaction.TRANSIT_NONE, ) { fm.beginTransaction() .setTransition(transaction) diff --git a/app/src/main/java/org/openedx/app/MainFragment.kt b/app/src/main/java/org/openedx/app/MainFragment.kt index fc4fb1b22..7087fee8f 100644 --- a/app/src/main/java/org/openedx/app/MainFragment.kt +++ b/app/src/main/java/org/openedx/app/MainFragment.kt @@ -11,13 +11,12 @@ import androidx.viewpager2.widget.ViewPager2 import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel -import org.openedx.DashboardNavigator import org.openedx.app.databinding.FragmentMainBinding import org.openedx.core.adapter.NavigationFragmentAdapter import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment import org.openedx.core.presentation.global.viewBinding -import org.openedx.discovery.presentation.DiscoveryNavigator import org.openedx.discovery.presentation.DiscoveryRouter +import org.openedx.learn.presentation.LearnFragment import org.openedx.profile.presentation.profile.ProfileFragment class MainFragment : Fragment(R.layout.fragment_main) { @@ -97,12 +96,9 @@ class MainFragment : Fragment(R.layout.fragment_main) { binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL binding.viewPager.offscreenPageLimit = 4 - val discoveryFragment = DiscoveryNavigator(viewModel.isDiscoveryTypeWebView).getDiscoveryFragment() - val dashboardFragment = DashboardNavigator(viewModel.dashboardType).getDashboardFragment() - adapter = NavigationFragmentAdapter(this).apply { - addFragment(dashboardFragment) - addFragment(discoveryFragment) + addFragment(LearnFragment()) + addFragment(viewModel.getDiscoveryFragment) addFragment(ProfileFragment()) } binding.viewPager.adapter = adapter diff --git a/app/src/main/java/org/openedx/app/MainViewModel.kt b/app/src/main/java/org/openedx/app/MainViewModel.kt index eed901039..f3d62c04f 100644 --- a/app/src/main/java/org/openedx/app/MainViewModel.kt +++ b/app/src/main/java/org/openedx/app/MainViewModel.kt @@ -14,6 +14,8 @@ import org.openedx.core.BaseViewModel import org.openedx.core.config.Config import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.core.system.notifier.NavigationToDiscovery +import org.openedx.dashboard.presentation.DashboardRouter +import org.openedx.discovery.presentation.DiscoveryNavigator class MainViewModel( private val config: Config, @@ -30,7 +32,7 @@ class MainViewModel( get() = _navigateToDiscovery.asSharedFlow() val isDiscoveryTypeWebView get() = config.getDiscoveryConfig().isViewTypeWebView() - val dashboardType get() = config.getDashboardConfig().getType() + val getDiscoveryFragment get() = DiscoveryNavigator(isDiscoveryTypeWebView).getDiscoveryFragment() override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) diff --git a/dashboard/src/main/java/org/openedx/DashboardNavigator.kt b/dashboard/src/main/java/org/openedx/DashboardNavigator.kt index 9e5f4c900..1705860b6 100644 --- a/dashboard/src/main/java/org/openedx/DashboardNavigator.kt +++ b/dashboard/src/main/java/org/openedx/DashboardNavigator.kt @@ -2,15 +2,15 @@ package org.openedx import androidx.fragment.app.Fragment import org.openedx.core.config.DashboardConfig +import org.openedx.courses.presentation.DashboardGalleryFragment import org.openedx.dashboard.presentation.DashboardListFragment -import org.openedx.learn.presentation.LearnFragment class DashboardNavigator( private val dashboardType: DashboardConfig.DashboardType, ) { fun getDashboardFragment(): Fragment { return when (dashboardType) { - DashboardConfig.DashboardType.GALLERY -> LearnFragment() + DashboardConfig.DashboardType.GALLERY -> DashboardGalleryFragment() else -> DashboardListFragment() } } diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index 0a7f59c93..31aaa2e3c 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -42,6 +42,7 @@ 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.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable @@ -84,13 +85,11 @@ import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRecommendedBox import org.openedx.core.system.notifier.AppUpgradeEvent import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.OfflineModeDialog -import org.openedx.core.ui.Toolbar 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.shouldLoadMore -import org.openedx.core.ui.statusBarsInset import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appShapes @@ -158,9 +157,6 @@ class DashboardListFragment : Fragment() { AppUpdateState.openPlayMarket(requireContext()) }, ), - onSettingsClick = { - router.navigateToSettings(requireActivity().supportFragmentManager) - } ) } } @@ -180,7 +176,6 @@ internal fun DashboardListView( onReloadClick: () -> Unit, onSwipeRefresh: () -> Unit, paginationCallback: () -> Unit, - onSettingsClick: () -> Unit, onItemClick: (EnrolledCourse) -> Unit, appUpgradeParameters: AppUpdateState.AppUpgradeParameters, ) { @@ -193,7 +188,7 @@ internal fun DashboardListView( } val scrollState = rememberLazyListState() val firstVisibleIndex = remember { - mutableStateOf(scrollState.firstVisibleItemIndex) + mutableIntStateOf(scrollState.firstVisibleItemIndex) } Scaffold( @@ -244,15 +239,9 @@ internal fun DashboardListView( Column( modifier = Modifier .padding(paddingValues) - .statusBarsInset() .displayCutoutForLandscape(), horizontalAlignment = Alignment.CenterHorizontally ) { - Toolbar( - label = stringResource(id = R.string.dashboard_title), - canShowSettingsIcon = true, - onSettingsClick = onSettingsClick - ) Surface( color = MaterialTheme.appColors.background, @@ -285,12 +274,6 @@ internal fun DashboardListView( state = scrollState, contentPadding = contentPaddings, content = { - item() { - Column { - Header() - Spacer(modifier = Modifier.height(16.dp)) - } - } items(state.courses) { course -> CourseItem( apiHostUrl, @@ -329,7 +312,6 @@ internal fun DashboardListView( .then(contentWidth) .then(emptyStatePaddings) ) { - Header() EmptyState() } } @@ -491,24 +473,6 @@ private fun CourseItem( } } -@Composable -private fun Header() { - Text( - modifier = Modifier.testTag("txt_courses_title"), - text = stringResource(id = R.string.dashboard_courses), - color = MaterialTheme.appColors.textPrimary, - style = MaterialTheme.appTypography.displaySmall - ) - Text( - modifier = Modifier - .testTag("txt_courses_description") - .padding(top = 4.dp), - text = stringResource(id = R.string.dashboard_welcome_back), - color = MaterialTheme.appColors.textPrimaryVariant, - style = MaterialTheme.appTypography.titleSmall - ) -} - @Composable private fun EmptyState() { Box( @@ -542,7 +506,7 @@ private fun EmptyState() { @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CourseItemPreview() { - OpenEdXTheme() { + OpenEdXTheme { CourseItem( "http://localhost:8000", mockCourseEnrolled, @@ -577,7 +541,6 @@ private fun DashboardListViewPreview() { refreshing = false, canLoadMore = false, paginationCallback = {}, - onSettingsClick = {}, appUpgradeParameters = AppUpdateState.AppUpgradeParameters() ) } @@ -609,7 +572,6 @@ private fun DashboardListViewTabletPreview() { refreshing = false, canLoadMore = false, paginationCallback = {}, - onSettingsClick = {}, appUpgradeParameters = AppUpdateState.AppUpgradeParameters() ) } diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt index 4d9b5cdbc..2c712bad6 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt @@ -20,5 +20,5 @@ interface DashboardRouter { fun navigateToAllEnrolledCourses(fm: FragmentManager) - fun getProgramFragmentInstance(): Fragment + fun getProgramFragment(): Fragment } diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt index b2de66cd4..7a79f3c2e 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt @@ -39,8 +39,8 @@ import androidx.compose.ui.unit.dp import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.viewpager2.widget.ViewPager2 -import org.koin.android.ext.android.inject import org.koin.androidx.compose.koinViewModel +import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.core.adapter.NavigationFragmentAdapter import org.openedx.core.presentation.global.viewBinding import org.openedx.core.ui.crop @@ -51,17 +51,15 @@ 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.courses.presentation.DashboardGalleryFragment import org.openedx.dashboard.R import org.openedx.dashboard.databinding.FragmentLearnBinding -import org.openedx.dashboard.presentation.DashboardRouter import org.openedx.learn.LearnType import org.openedx.core.R as CoreR class LearnFragment : Fragment(R.layout.fragment_learn) { private val binding by viewBinding(FragmentLearnBinding::bind) - private val router by inject() + private val viewModel by viewModel() private lateinit var adapter: NavigationFragmentAdapter override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -82,8 +80,8 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { binding.viewPager.offscreenPageLimit = 2 adapter = NavigationFragmentAdapter(this).apply { - addFragment(DashboardGalleryFragment()) - addFragment(router.getProgramFragmentInstance()) + addFragment(viewModel.getDashboardFragment) + addFragment(viewModel.getProgramFragment) } binding.viewPager.adapter = adapter binding.viewPager.setUserInputEnabled(false) @@ -93,7 +91,7 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { @Composable private fun Header( fragmentManager: FragmentManager, - viewPager: ViewPager2 + viewPager: ViewPager2, ) { val viewModel: LearnViewModel = koinViewModel() val windowSize = rememberWindowSize() @@ -120,7 +118,6 @@ private fun Header( viewModel.onSettingsClick(fragmentManager) } ) - if (viewModel.isProgramTypeWebView) { LearnDropdownMenu( modifier = Modifier @@ -136,7 +133,7 @@ private fun Header( private fun Title( modifier: Modifier = Modifier, label: String, - onSettingsClick: () -> Unit + onSettingsClick: () -> Unit, ) { Box( modifier = modifier.fillMaxWidth() @@ -169,7 +166,7 @@ private fun Title( @Composable private fun LearnDropdownMenu( modifier: Modifier = Modifier, - viewPager: ViewPager2 + viewPager: ViewPager2, ) { var expanded by remember { mutableStateOf(false) } var currentValue by remember { mutableStateOf(LearnType.COURSES) } @@ -212,7 +209,12 @@ private fun LearnDropdownMenu( MaterialTheme( colors = MaterialTheme.colors.copy(surface = MaterialTheme.appColors.background), - shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp)) + shapes = MaterialTheme.shapes.copy( + medium = RoundedCornerShape( + bottomStart = 8.dp, + bottomEnd = 8.dp + ) + ) ) { DropdownMenu( modifier = Modifier diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt index d2300f652..62ee774cb 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt @@ -1,18 +1,24 @@ package org.openedx.learn.presentation import androidx.fragment.app.FragmentManager +import org.openedx.DashboardNavigator import org.openedx.core.BaseViewModel import org.openedx.core.config.Config import org.openedx.dashboard.presentation.DashboardRouter class LearnViewModel( private val config: Config, - private val dashboardRouter: DashboardRouter + private val dashboardRouter: DashboardRouter, ) : BaseViewModel() { + private val dashboardType get() = config.getDashboardConfig().getType() val isProgramTypeWebView get() = config.getProgramConfig().isViewTypeWebView() fun onSettingsClick(fragmentManager: FragmentManager) { dashboardRouter.navigateToSettings(fragmentManager) } + + val getDashboardFragment get() = DashboardNavigator(dashboardType).getDashboardFragment() + + val getProgramFragment get() = dashboardRouter.getProgramFragment() } diff --git a/dashboard/src/main/res/values-uk/strings.xml b/dashboard/src/main/res/values-uk/strings.xml index a7b3ef9d3..bf1c7da16 100644 --- a/dashboard/src/main/res/values-uk/strings.xml +++ b/dashboard/src/main/res/values-uk/strings.xml @@ -1,8 +1,6 @@ - Мої курси Курси - Ласкаво просимо назад. Продовжуймо навчатися. You are not enrolled in any courses yet. \ No newline at end of file diff --git a/dashboard/src/main/res/values/strings.xml b/dashboard/src/main/res/values/strings.xml index 23a33fb50..f83c35a2f 100644 --- a/dashboard/src/main/res/values/strings.xml +++ b/dashboard/src/main/res/values/strings.xml @@ -1,8 +1,6 @@ - Dashboard Courses - Welcome back. Let\'s keep learning. You are not enrolled in any courses yet. Learn Programs diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt index 3b74dbc42..ef79e1f32 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt @@ -46,6 +46,7 @@ import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.core.extension.loadUrl +import org.openedx.core.extension.takeIfNotEmpty import org.openedx.core.extension.toastMessage import org.openedx.core.presentation.dialog.alert.ActionDialogFragment import org.openedx.core.presentation.dialog.alert.InfoDialogFragment @@ -68,16 +69,15 @@ import org.openedx.discovery.presentation.catalog.WebViewLink import org.openedx.core.R as coreR import org.openedx.discovery.presentation.catalog.WebViewLink.Authority as linkAuthority -class ProgramFragment( - private val myPrograms: Boolean = false, - private val isNestedFragment: Boolean = false -) : Fragment() { +class ProgramFragment : Fragment() { private val viewModel by viewModel() + private var isNestedFragment = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (myPrograms.not()) { + isNestedFragment = arguments?.getBoolean(ARG_NESTED_FRAGMENT, false) ?: false + if (isNestedFragment.not()) { lifecycle.addObserver(viewModel) } } @@ -85,7 +85,7 @@ class ProgramFragment( override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ) = ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { @@ -96,7 +96,7 @@ class ProgramFragment( mutableStateOf(viewModel.hasInternetConnection) } - if (myPrograms.not()) { + if (isNestedFragment.not()) { DisposableEffect(uiState is ProgramUIState.CourseEnrolled) { if (uiState is ProgramUIState.CourseEnrolled) { @@ -157,7 +157,8 @@ class ProgramFragment( } linkAuthority.PROGRAM_INFO, - linkAuthority.COURSE_INFO -> { + linkAuthority.COURSE_INFO, + -> { viewModel.onViewCourseClick( fragmentManager = requireActivity().supportFragmentManager, courseId = param, @@ -198,23 +199,26 @@ class ProgramFragment( } private fun getInitialUrl(): String { - return arguments?.let { args -> - val pathId = args.getString(ARG_PATH_ID) ?: "" - viewModel.programConfig.programDetailUrlTemplate.replace("{$ARG_PATH_ID}", pathId) + val pathId = arguments?.getString(ARG_PATH_ID, "") + return pathId?.takeIfNotEmpty()?.let { + viewModel.programConfig.programDetailUrlTemplate.replace("{$ARG_PATH_ID}", it) } ?: viewModel.programConfig.programUrl } companion object { private const val ARG_PATH_ID = "path_id" + private const val ARG_NESTED_FRAGMENT = "nested_fragment" fun newInstance( - pathId: String, + pathId: String = "", + isNestedFragment: Boolean = false, ): ProgramFragment { - val fragment = ProgramFragment(false) - fragment.arguments = bundleOf( - ARG_PATH_ID to pathId, - ) - return fragment + return ProgramFragment().apply { + arguments = bundleOf( + ARG_PATH_ID to pathId, + ARG_NESTED_FRAGMENT to isNestedFragment + ) + } } } } From 7d623ce72b87814a9da8aee309b103fc68d2726e Mon Sep 17 00:00:00 2001 From: PavloNetrebchuk <141041606+PavloNetrebchuk@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:03:23 +0300 Subject: [PATCH 12/38] fix: Filter block IDs before download, minor refactoring (#333) --- .../outline/CourseOutlineScreen.kt | 21 +++++-------------- .../outline/CourseOutlineViewModel.kt | 19 +++++++++++++++++ .../course/presentation/ui/CourseUI.kt | 7 ++++--- .../course/presentation/ui/CourseVideosUI.kt | 12 ----------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt index 1a29819f2..1f31b32de 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt @@ -65,7 +65,6 @@ 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.core.utils.FileUtil import org.openedx.course.R import org.openedx.course.presentation.ui.CourseDatesBanner import org.openedx.course.presentation.ui.CourseDatesBannerTablet @@ -138,21 +137,11 @@ fun CourseOutlineScreen( ) }, onDownloadClick = { blocksIds -> - blocksIds.forEach { blockId -> - if (viewModel.isBlockDownloading(blockId)) { - viewModel.courseRouter.navigateToDownloadQueue( - fm = fragmentManager, - viewModel.getDownloadableChildren(blockId) - ?: arrayListOf() - ) - } else if (viewModel.isBlockDownloaded(blockId)) { - viewModel.removeDownloadModels(blockId) - } else { - viewModel.saveDownloadModels( - FileUtil(context).getExternalAppDir().path, blockId - ) - } - } + viewModel.downloadBlocks( + blocksIds = blocksIds, + fragmentManager = fragmentManager, + context = context + ) }, onResetDatesClick = { viewModel.resetCourseDatesBanner( 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 602c7d2fa..6ea080957 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 @@ -1,5 +1,6 @@ package org.openedx.course.presentation.outline +import android.content.Context import androidx.fragment.app.FragmentManager import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableSharedFlow @@ -36,6 +37,7 @@ import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseOpenBlock import org.openedx.core.system.notifier.CourseStructureUpdated +import org.openedx.core.utils.FileUtil import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics import org.openedx.course.presentation.CourseAnalyticsEvent @@ -385,4 +387,21 @@ class CourseOutlineViewModel( ) } } + + fun downloadBlocks(blocksIds: List, fragmentManager: FragmentManager, context: Context) { + blocksIds.forEach { blockId -> + if (isBlockDownloading(blockId)) { + courseRouter.navigateToDownloadQueue( + fm = fragmentManager, + getDownloadableChildren(blockId) ?: arrayListOf() + ) + } else if (isBlockDownloaded(blockId)) { + removeDownloadModels(blockId) + } else { + saveDownloadModels( + FileUtil(context).getExternalAppDir().path, blockId + ) + } + } + } } 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 27da57afb..7d8729fac 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 @@ -595,14 +595,15 @@ fun CourseSection( val arrowRotation by animateFloatAsState( targetValue = if (courseSectionsState == true) -90f else 90f, label = "" ) - val sectionIds = courseSubSections?.map { it.id }.orEmpty() - val filteredStatuses = downloadedStateMap.filterKeys { it in sectionIds }.values + val subSectionIds = courseSubSections?.map { it.id }.orEmpty() + val filteredStatuses = downloadedStateMap.filterKeys { it in subSectionIds }.values val downloadedState = when { filteredStatuses.isEmpty() -> null filteredStatuses.all { it.isDownloaded } -> DownloadedState.DOWNLOADED filteredStatuses.any { it.isWaitingOrDownloading } -> DownloadedState.DOWNLOADING else -> DownloadedState.NOT_DOWNLOADED } + val downloadBlockIds = downloadedStateMap.keys.filter { it in block.descendants } Column(modifier = modifier .clip(MaterialTheme.appShapes.cardShape) @@ -619,7 +620,7 @@ fun CourseSection( arrowDegrees = arrowRotation, downloadedState = downloadedState, onDownloadClick = { - onDownloadClick(downloadedStateMap.keys.toList()) + onDownloadClick(downloadBlockIds) } ) courseSubSections?.forEach { subSectionBlock -> diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt index 7beb0f91d..1a406181d 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt @@ -99,14 +99,6 @@ fun CourseVideosScreen( uiMessage = uiMessage, courseTitle = viewModel.courseTitle, videoSettings = videoSettings, - onItemClick = { block -> - viewModel.courseRouter.navigateToCourseSubsections( - fm = fragmentManager, - courseId = viewModel.courseId, - subSectionId = block.id, - mode = CourseViewMode.VIDEOS - ) - }, onExpandClick = { block -> viewModel.switchCourseSections(block.id) }, @@ -166,7 +158,6 @@ private fun CourseVideosUI( uiMessage: UIMessage?, courseTitle: String, videoSettings: VideoSettings, - onItemClick: (Block) -> Unit, onExpandClick: (Block) -> Unit, onSubSectionClick: (Block) -> Unit, onDownloadClick: (blocksIds: List) -> Unit, @@ -636,7 +627,6 @@ private fun CourseVideosScreenPreview() { ) ), courseTitle = "", - onItemClick = { }, onExpandClick = { }, onSubSectionClick = { }, videoSettings = VideoSettings.default, @@ -660,7 +650,6 @@ private fun CourseVideosScreenEmptyPreview() { "This course does not include any videos." ), courseTitle = "", - onItemClick = { }, onExpandClick = { }, onSubSectionClick = { }, videoSettings = VideoSettings.default, @@ -695,7 +684,6 @@ private fun CourseVideosScreenTabletPreview() { ) ), courseTitle = "", - onItemClick = { }, onExpandClick = { }, onSubSectionClick = { }, videoSettings = VideoSettings.default, From 651db4c5f0b04e67f86aa7f731706993bf370948 Mon Sep 17 00:00:00 2001 From: PavloNetrebchuk <141041606+PavloNetrebchuk@users.noreply.github.com> Date: Fri, 7 Jun 2024 21:44:57 +0300 Subject: [PATCH 13/38] fix: Update feature flag name (#334) --- default_config/dev/config.yaml | 2 +- default_config/prod/config.yaml | 2 +- default_config/stage/config.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/default_config/dev/config.yaml b/default_config/dev/config.yaml index 8b1dc8f07..da6687b2e 100644 --- a/default_config/dev/config.yaml +++ b/default_config/dev/config.yaml @@ -80,5 +80,5 @@ WHATS_NEW_ENABLED: false SOCIAL_AUTH_ENABLED: false #Course navigation feature flags UI_COMPONENTS: - COURSE_NESTED_LIST_ENABLED: false + COURSE_DROPDOWN_NAVIGATION_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false diff --git a/default_config/prod/config.yaml b/default_config/prod/config.yaml index 8b1dc8f07..da6687b2e 100644 --- a/default_config/prod/config.yaml +++ b/default_config/prod/config.yaml @@ -80,5 +80,5 @@ WHATS_NEW_ENABLED: false SOCIAL_AUTH_ENABLED: false #Course navigation feature flags UI_COMPONENTS: - COURSE_NESTED_LIST_ENABLED: false + COURSE_DROPDOWN_NAVIGATION_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false diff --git a/default_config/stage/config.yaml b/default_config/stage/config.yaml index 8b1dc8f07..da6687b2e 100644 --- a/default_config/stage/config.yaml +++ b/default_config/stage/config.yaml @@ -80,5 +80,5 @@ WHATS_NEW_ENABLED: false SOCIAL_AUTH_ENABLED: false #Course navigation feature flags UI_COMPONENTS: - COURSE_NESTED_LIST_ENABLED: false + COURSE_DROPDOWN_NAVIGATION_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false From 21bd1a17233025e8690623b90e3c2d9c81efe594 Mon Sep 17 00:00:00 2001 From: Volodymyr Chekyrta <127732735+volodymyr-chekyrta@users.noreply.github.com> Date: Sat, 8 Jun 2024 11:15:41 +0300 Subject: [PATCH 14/38] fix: sourceSets dir fallback (#335) --- app/build.gradle | 8 ++++---- core/build.gradle | 14 +++++++------- default_config/dev/config.yaml | 2 ++ default_config/prod/config.yaml | 2 ++ default_config/stage/config.yaml | 2 ++ 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2b0ab4f74..86363a2b7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,6 @@ def config = configHelper.fetchConfig() def appId = config.getOrDefault("APPLICATION_ID", "org.openedx.app") -def platformName = config.getOrDefault("PLATFORM_NAME", "OpenEdx").toLowerCase() +def themeDirectory = config.getOrDefault("THEME_DIRECTORY", "openedx") def firebaseConfig = config.get('FIREBASE') def firebaseEnabled = firebaseConfig?.getOrDefault('ENABLED', false) @@ -63,13 +63,13 @@ android { sourceSets { prod { - res.srcDirs = ["src/$platformName/res"] + res.srcDirs = ["src/$themeDirectory/res"] } develop { - res.srcDirs = ["src/$platformName/res"] + res.srcDirs = ["src/$themeDirectory/res"] } stage { - res.srcDirs = ["src/$platformName/res"] + res.srcDirs = ["src/$themeDirectory/res"] } } diff --git a/core/build.gradle b/core/build.gradle index f69d633cb..f5dc7841f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -17,7 +17,7 @@ plugins { def currentFlavour = getCurrentFlavor() def config = configHelper.fetchConfig() -def platformName = config.getOrDefault("PLATFORM_NAME", "OpenEdx").toLowerCase() +def themeDirectory = config.getOrDefault("THEME_DIRECTORY", "openedx") android { compileSdk 34 @@ -50,16 +50,16 @@ android { sourceSets { prod { - java.srcDirs = ["src/$platformName"] - res.srcDirs = ["src/$platformName/res"] + java.srcDirs = ["src/$themeDirectory"] + res.srcDirs = ["src/$themeDirectory/res"] } develop { - java.srcDirs = ["src/$platformName"] - res.srcDirs = ["src/$platformName/res"] + java.srcDirs = ["src/$themeDirectory"] + res.srcDirs = ["src/$themeDirectory/res"] } stage { - java.srcDirs = ["src/$platformName"] - res.srcDirs = ["src/$platformName/res"] + java.srcDirs = ["src/$themeDirectory"] + res.srcDirs = ["src/$themeDirectory/res"] } main { assets { diff --git a/default_config/dev/config.yaml b/default_config/dev/config.yaml index da6687b2e..eee22e36d 100644 --- a/default_config/dev/config.yaml +++ b/default_config/dev/config.yaml @@ -72,6 +72,8 @@ BRANCH: #Platform names PLATFORM_NAME: "OpenEdX" PLATFORM_FULL_NAME: "OpenEdX" +#App sourceSets dir +THEME_DIRECTORY: "openedx" #tokenType enum accepts JWT and BEARER only TOKEN_TYPE: "JWT" #feature flag for activating What’s New feature diff --git a/default_config/prod/config.yaml b/default_config/prod/config.yaml index da6687b2e..eee22e36d 100644 --- a/default_config/prod/config.yaml +++ b/default_config/prod/config.yaml @@ -72,6 +72,8 @@ BRANCH: #Platform names PLATFORM_NAME: "OpenEdX" PLATFORM_FULL_NAME: "OpenEdX" +#App sourceSets dir +THEME_DIRECTORY: "openedx" #tokenType enum accepts JWT and BEARER only TOKEN_TYPE: "JWT" #feature flag for activating What’s New feature diff --git a/default_config/stage/config.yaml b/default_config/stage/config.yaml index da6687b2e..eee22e36d 100644 --- a/default_config/stage/config.yaml +++ b/default_config/stage/config.yaml @@ -72,6 +72,8 @@ BRANCH: #Platform names PLATFORM_NAME: "OpenEdX" PLATFORM_FULL_NAME: "OpenEdX" +#App sourceSets dir +THEME_DIRECTORY: "openedx" #tokenType enum accepts JWT and BEARER only TOKEN_TYPE: "JWT" #feature flag for activating What’s New feature From 07f6dcacbfc80e2cb42bb2e197d2cb9dff9c4a00 Mon Sep 17 00:00:00 2001 From: Omer Habib <30689349+omerhabib26@users.noreply.github.com> Date: Sat, 8 Jun 2024 13:16:22 +0500 Subject: [PATCH 15/38] fix: Crash on opening a course from DashboardListFragment (#336) - Replace the fragmentManager of parentFragment with activity fix: LEARNER-10035 --- .../org/openedx/dashboard/presentation/DashboardListFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index 31aaa2e3c..e3d6abdf6 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -139,7 +139,7 @@ class DashboardListFragment : Fragment() { onItemClick = { viewModel.dashboardCourseClickedEvent(it.course.id, it.course.name) router.navigateToCourseOutline( - requireParentFragment().parentFragmentManager, + requireActivity().supportFragmentManager, it.course.id, it.course.name, it.mode From d845e5ee72a313e63522ec3e7f641f583b6f1555 Mon Sep 17 00:00:00 2001 From: Igor Date: Mon, 10 Jun 2024 10:12:40 +0200 Subject: [PATCH 16/38] feat: added the external router for deep links (#320) --- app/src/main/AndroidManifest.xml | 3 +- .../main/java/org/openedx/app/AppActivity.kt | 11 +- .../main/java/org/openedx/app/AppRouter.kt | 16 +- .../main/java/org/openedx/app/AppViewModel.kt | 8 + .../main/java/org/openedx/app/MainFragment.kt | 38 +- .../java/org/openedx/app/deeplink/DeepLink.kt | 22 + .../openedx/app/deeplink/DeepLinkRouter.kt | 507 ++++++++++++++++++ .../java/org/openedx/app/deeplink/HomeTab.kt | 8 + .../java/org/openedx/app/deeplink/Screen.kt | 20 + .../main/java/org/openedx/app/di/AppModule.kt | 2 + .../java/org/openedx/app/di/ScreenModule.kt | 2 +- .../test/java/org/openedx/AppViewModelTest.kt | 5 + .../openedx/auth/presentation/AuthRouter.kt | 7 +- .../course/presentation/CourseRouter.kt | 2 +- .../container/CourseContainerFragment.kt | 6 +- .../handouts/HandoutsWebViewFragment.kt | 20 +- .../learn/presentation/LearnFragment.kt | 29 +- .../openedx/learn/presentation/LearnTab.kt | 6 + .../detail/CourseDetailsFragment.kt | 2 +- .../presentation/info/CourseInfoViewModel.kt | 2 +- .../discussion/data/api/DiscussionApi.kt | 15 + .../data/repository/DiscussionRepository.kt | 16 +- .../domain/interactor/DiscussionInteractor.kt | 12 +- .../org/openedx/whatsnew/WhatsNewRouter.kt | 7 +- .../whatsnew/WhatsNewViewModel.kt | 3 +- 25 files changed, 730 insertions(+), 39 deletions(-) create mode 100644 app/src/main/java/org/openedx/app/deeplink/DeepLink.kt create mode 100644 app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt create mode 100644 app/src/main/java/org/openedx/app/deeplink/HomeTab.kt create mode 100644 app/src/main/java/org/openedx/app/deeplink/Screen.kt create mode 100644 dashboard/src/main/java/org/openedx/learn/presentation/LearnTab.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3e8282acb..efc65add4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -41,7 +41,8 @@ android:exported="true" android:fitsSystemWindows="true" android:theme="@style/Theme.App.Starting" - android:windowSoftInputMode="adjustPan"> + android:windowSoftInputMode="adjustPan" + android:launchMode="singleInstance"> diff --git a/app/src/main/java/org/openedx/app/AppActivity.kt b/app/src/main/java/org/openedx/app/AppActivity.kt index 5ab0d0b0e..9781b0ca7 100644 --- a/app/src/main/java/org/openedx/app/AppActivity.kt +++ b/app/src/main/java/org/openedx/app/AppActivity.kt @@ -18,6 +18,7 @@ import io.branch.referral.Branch.BranchUniversalReferralInitListener import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.app.databinding.ActivityAppBinding +import org.openedx.app.deeplink.DeepLink import org.openedx.auth.presentation.logistration.LogistrationFragment import org.openedx.auth.presentation.signin.SignInFragment import org.openedx.core.data.storage.CorePreferences @@ -145,10 +146,14 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder { super.onStart() if (viewModel.isBranchEnabled) { - val callback = BranchUniversalReferralInitListener { _, linkProperties, error -> - if (linkProperties != null) { + val callback = BranchUniversalReferralInitListener { branchUniversalObject, _, error -> + if (branchUniversalObject?.contentMetadata?.customMetadata != null) { branchLogger.i { "Branch init complete." } - branchLogger.i { linkProperties.controlParams.toString() } + branchLogger.i { branchUniversalObject.contentMetadata.customMetadata.toString() } + viewModel.makeExternalRoute( + fm = supportFragmentManager, + deepLink = DeepLink(branchUniversalObject.contentMetadata.customMetadata) + ) } else if (error != null) { branchLogger.e { "Branch init failed. Caused by -" + error.message } } diff --git a/app/src/main/java/org/openedx/app/AppRouter.kt b/app/src/main/java/org/openedx/app/AppRouter.kt index fe4394cde..99eb919dc 100644 --- a/app/src/main/java/org/openedx/app/AppRouter.kt +++ b/app/src/main/java/org/openedx/app/AppRouter.kt @@ -59,10 +59,15 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di ProfileRouter, AppUpgradeRouter, WhatsNewRouter { //region AuthRouter - override fun navigateToMain(fm: FragmentManager, courseId: String?, infoType: String?) { + override fun navigateToMain( + fm: FragmentManager, + courseId: String?, + infoType: String?, + openTab: String + ) { fm.popBackStack() fm.beginTransaction() - .replace(R.id.container, MainFragment.newInstance(courseId, infoType)) + .replace(R.id.container, MainFragment.newInstance(courseId, infoType, openTab)) .commit() } @@ -286,12 +291,11 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di override fun navigateToHandoutsWebView( fm: FragmentManager, courseId: String, - title: String, type: HandoutsType, ) { replaceFragmentWithBackStack( fm, - HandoutsWebViewFragment.newInstance(title, type.name, courseId) + HandoutsWebViewFragment.newInstance(type.name, courseId) ) } //endregion @@ -409,6 +413,10 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di } //endregion + fun getVisibleFragment(fm: FragmentManager): Fragment? { + return fm.fragments.firstOrNull { it.isVisible } + } + private fun replaceFragmentWithBackStack(fm: FragmentManager, fragment: Fragment) { fm.beginTransaction() .replace(R.id.container, fragment, fragment.javaClass.simpleName) diff --git a/app/src/main/java/org/openedx/app/AppViewModel.kt b/app/src/main/java/org/openedx/app/AppViewModel.kt index c18e48026..3fc49859f 100644 --- a/app/src/main/java/org/openedx/app/AppViewModel.kt +++ b/app/src/main/java/org/openedx/app/AppViewModel.kt @@ -1,5 +1,6 @@ package org.openedx.app +import androidx.fragment.app.FragmentManager import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope @@ -7,6 +8,8 @@ import androidx.room.RoomDatabase import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.openedx.app.deeplink.DeepLink +import org.openedx.app.deeplink.DeepLinkRouter import org.openedx.app.system.notifier.AppNotifier import org.openedx.app.system.notifier.LogoutEvent import org.openedx.core.BaseViewModel @@ -22,6 +25,7 @@ class AppViewModel( private val preferencesManager: CorePreferences, private val dispatcher: CoroutineDispatcher, private val analytics: AppAnalytics, + private val deepLinkRouter: DeepLinkRouter, private val fileUtil: FileUtil, ) : BaseViewModel() { @@ -71,6 +75,10 @@ class AppViewModel( preferencesManager.canResetAppDirectory = false } + fun makeExternalRoute(fm: FragmentManager, deepLink: DeepLink) { + deepLinkRouter.makeRoute(fm, deepLink) + } + private fun setUserId() { preferencesManager.user?.let { analytics.setUserIdForSession(it.id) diff --git a/app/src/main/java/org/openedx/app/MainFragment.kt b/app/src/main/java/org/openedx/app/MainFragment.kt index 7087fee8f..62857ee9f 100644 --- a/app/src/main/java/org/openedx/app/MainFragment.kt +++ b/app/src/main/java/org/openedx/app/MainFragment.kt @@ -12,11 +12,13 @@ import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.app.databinding.FragmentMainBinding +import org.openedx.app.deeplink.HomeTab import org.openedx.core.adapter.NavigationFragmentAdapter import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment import org.openedx.core.presentation.global.viewBinding import org.openedx.discovery.presentation.DiscoveryRouter import org.openedx.learn.presentation.LearnFragment +import org.openedx.learn.presentation.LearnTab import org.openedx.profile.presentation.profile.ProfileFragment class MainFragment : Fragment(R.layout.fragment_main) { @@ -60,8 +62,6 @@ class MainFragment : Fragment(R.layout.fragment_main) { } true } - // Trigger click event for the first tab on initial load - binding.bottomNavView.selectedItemId = binding.bottomNavView.selectedItemId viewModel.isBottomBarEnabled.observe(viewLifecycleOwner) { isBottomBarEnabled -> enableBottomBar(isBottomBarEnabled) @@ -89,6 +89,22 @@ class MainFragment : Fragment(R.layout.fragment_main) { putString(ARG_COURSE_ID, "") putString(ARG_INFO_TYPE, "") } + + when (requireArguments().getString(ARG_OPEN_TAB, HomeTab.LEARN.name)) { + HomeTab.LEARN.name, + HomeTab.PROGRAMS.name -> { + binding.bottomNavView.selectedItemId = R.id.fragmentLearn + } + + HomeTab.DISCOVER.name -> { + binding.bottomNavView.selectedItemId = R.id.fragmentDiscover + } + + HomeTab.PROFILE.name -> { + binding.bottomNavView.selectedItemId = R.id.fragmentProfile + } + } + requireArguments().remove(ARG_OPEN_TAB) } } @@ -96,8 +112,14 @@ class MainFragment : Fragment(R.layout.fragment_main) { binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL binding.viewPager.offscreenPageLimit = 4 + val openTab = requireArguments().getString(ARG_OPEN_TAB, HomeTab.LEARN.name) + val learnTab = if (openTab == HomeTab.PROGRAMS.name) { + LearnTab.PROGRAMS + } else { + LearnTab.COURSES + } adapter = NavigationFragmentAdapter(this).apply { - addFragment(LearnFragment()) + addFragment(LearnFragment.newInstance(openTab = learnTab.name)) addFragment(viewModel.getDiscoveryFragment) addFragment(ProfileFragment()) } @@ -114,11 +136,17 @@ class MainFragment : Fragment(R.layout.fragment_main) { companion object { private const val ARG_COURSE_ID = "courseId" private const val ARG_INFO_TYPE = "info_type" - fun newInstance(courseId: String? = null, infoType: String? = null): MainFragment { + private const val ARG_OPEN_TAB = "open_tab" + fun newInstance( + courseId: String? = null, + infoType: String? = null, + openTab: String = HomeTab.LEARN.name + ): MainFragment { val fragment = MainFragment() fragment.arguments = bundleOf( ARG_COURSE_ID to courseId, - ARG_INFO_TYPE to infoType + ARG_INFO_TYPE to infoType, + ARG_OPEN_TAB to openTab ) return fragment } diff --git a/app/src/main/java/org/openedx/app/deeplink/DeepLink.kt b/app/src/main/java/org/openedx/app/deeplink/DeepLink.kt new file mode 100644 index 000000000..2b65a92b1 --- /dev/null +++ b/app/src/main/java/org/openedx/app/deeplink/DeepLink.kt @@ -0,0 +1,22 @@ +package org.openedx.app.deeplink + +class DeepLink(params: Map) { + + val screenName = params[Keys.SCREEN_NAME.value] + val courseId = params[Keys.COURSE_ID.value] + val pathId = params[Keys.PATH_ID.value] + val componentId = params[Keys.COMPONENT_ID.value] + val topicId = params[Keys.TOPIC_ID.value] + val threadId = params[Keys.THREAD_ID.value] + val commentId = params[Keys.COMMENT_ID.value] + + enum class Keys(val value: String) { + SCREEN_NAME("screen_name"), + COURSE_ID("course_id"), + PATH_ID("path_id"), + COMPONENT_ID("component_id"), + TOPIC_ID("topic_id"), + THREAD_ID("thread_id"), + COMMENT_ID("comment_id") + } +} diff --git a/app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt b/app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt new file mode 100644 index 000000000..02bc5cd0e --- /dev/null +++ b/app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt @@ -0,0 +1,507 @@ +package org.openedx.app.deeplink + +import androidx.fragment.app.FragmentManager +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.openedx.app.AppRouter +import org.openedx.app.MainFragment +import org.openedx.app.R +import org.openedx.auth.presentation.signin.SignInFragment +import org.openedx.core.FragmentViewType +import org.openedx.core.config.Config +import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.presentation.course.CourseViewMode +import org.openedx.course.domain.interactor.CourseInteractor +import org.openedx.course.presentation.handouts.HandoutsType +import org.openedx.discovery.presentation.catalog.WebViewLink +import org.openedx.discussion.domain.interactor.DiscussionInteractor +import org.openedx.discussion.presentation.topics.DiscussionTopicsViewModel +import kotlin.coroutines.CoroutineContext + +class DeepLinkRouter( + private val config: Config, + private val appRouter: AppRouter, + private val corePreferences: CorePreferences, + private val courseInteractor: CourseInteractor, + private val discussionInteractor: DiscussionInteractor +) : CoroutineScope { + + override val coroutineContext: CoroutineContext + get() = Dispatchers.Default + + private val isUserLoggedIn + get() = corePreferences.user != null + + fun makeRoute(fm: FragmentManager, deepLink: DeepLink) { + val screenName = deepLink.screenName ?: return + when (screenName) { + // Discovery + Screen.DISCOVERY.screenName -> { + navigateToDiscoveryScreen(fm = fm) + return + } + + Screen.DISCOVERY_COURSE_DETAIL.screenName -> { + navigateToCourseDetail( + fm = fm, + deepLink = deepLink + ) + return + } + + Screen.DISCOVERY_PROGRAM_DETAIL.screenName -> { + navigateToProgramDetail( + fm = fm, + deepLink = deepLink + ) + return + } + } + + if (!isUserLoggedIn) { + navigateToSignIn(fm = fm) + return + } + + when (screenName) { + // Course + Screen.COURSE_DASHBOARD.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseDashboard( + fm = fm, + deepLink = deepLink + ) + } + + Screen.COURSE_VIDEOS.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseVideos( + fm = fm, + deepLink = deepLink + ) + } + + Screen.COURSE_DATES.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseDates( + fm = fm, + deepLink = deepLink + ) + } + + Screen.COURSE_DISCUSSION.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + } + + Screen.COURSE_HANDOUT.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseMore( + fm = fm, + deepLink = deepLink + ) + navigateToCourseHandout( + fm = fm, + deepLink = deepLink + ) + } + + Screen.COURSE_ANNOUNCEMENT.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseMore( + fm = fm, + deepLink = deepLink + ) + navigateToCourseAnnouncement( + fm = fm, + deepLink = deepLink + ) + } + + Screen.COURSE_COMPONENT.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseDashboard( + fm = fm, + deepLink = deepLink + ) + navigateToCourseComponent( + fm = fm, + deepLink = deepLink + ) + } + + // Program + Screen.PROGRAM.screenName -> { + navigateToProgram( + fm = fm, + deepLink = deepLink + ) + } + + // Discussions + Screen.DISCUSSION_TOPIC.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + navigateToDiscussionTopic( + fm = fm, + deepLink = deepLink + ) + } + + Screen.DISCUSSION_POST.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + navigateToDiscussionPost( + fm = fm, + deepLink = deepLink + ) + } + + Screen.DISCUSSION_COMMENT.screenName -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + navigateToDiscussionComment( + fm = fm, + deepLink = deepLink + ) + } + + // Profile + Screen.PROFILE.screenName, + Screen.USER_PROFILE.screenName -> { + navigateToProfile(fm = fm) + } + } + } + + // Returns true if there was a successful redirect to the discovery screen + private fun navigateToDiscoveryScreen(fm: FragmentManager): Boolean { + return if (isUserLoggedIn) { + fm.popBackStack() + fm.beginTransaction() + .replace(R.id.container, MainFragment.newInstance(openTab = "DISCOVER")) + .commitNow() + true + } else if (!config.isPreLoginExperienceEnabled()) { + navigateToSignIn(fm = fm) + false + } else if (config.getDiscoveryConfig().isViewTypeWebView()) { + appRouter.navigateToWebDiscoverCourses( + fm = fm, + querySearch = "" + ) + true + } else { + appRouter.navigateToNativeDiscoverCourses( + fm = fm, + querySearch = "" + ) + true + } + } + + private fun navigateToCourseDetail(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + if (navigateToDiscoveryScreen(fm = fm)) { + appRouter.navigateToCourseInfo( + fm = fm, + courseId = courseId, + infoType = WebViewLink.Authority.COURSE_INFO.name + ) + } + } + } + + private fun navigateToProgramDetail(fm: FragmentManager, deepLink: DeepLink) { + deepLink.pathId?.let { pathId -> + if (navigateToDiscoveryScreen(fm = fm)) { + appRouter.navigateToCourseInfo( + fm = fm, + courseId = pathId, + infoType = WebViewLink.Authority.PROGRAM_INFO.name + ) + } + } + } + + private fun navigateToSignIn(fm: FragmentManager) { + if (appRouter.getVisibleFragment(fm = fm) !is SignInFragment) { + appRouter.navigateToSignIn( + fm = fm, + courseId = null, + infoType = null + ) + } + } + + private fun navigateToCourseDashboard(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + appRouter.navigateToCourseOutline( + fm = fm, + courseId = courseId, + courseTitle = "", + enrollmentMode = "" + ) + } + } + + private fun navigateToCourseVideos(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + appRouter.navigateToCourseOutline( + fm = fm, + courseId = courseId, + courseTitle = "", + enrollmentMode = "", + openTab = "VIDEOS" + ) + } + } + + private fun navigateToCourseDates(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + appRouter.navigateToCourseOutline( + fm = fm, + courseId = courseId, + courseTitle = "", + enrollmentMode = "", + openTab = "DATES" + ) + } + } + + private fun navigateToCourseDiscussion(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + appRouter.navigateToCourseOutline( + fm = fm, + courseId = courseId, + courseTitle = "", + enrollmentMode = "", + openTab = "DISCUSSIONS" + ) + } + } + + private fun navigateToCourseMore(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + appRouter.navigateToCourseOutline( + fm = fm, + courseId = courseId, + courseTitle = "", + enrollmentMode = "", + openTab = "MORE" + ) + } + } + + private fun navigateToCourseHandout(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + appRouter.navigateToHandoutsWebView( + fm = fm, + courseId = courseId, + type = HandoutsType.Handouts + ) + } + } + + private fun navigateToCourseAnnouncement(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + appRouter.navigateToHandoutsWebView( + fm = fm, + courseId = courseId, + type = HandoutsType.Announcements + ) + } + } + + private fun navigateToCourseComponent(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + deepLink.componentId?.let { componentId -> + launch { + try { + val courseStructure = courseInteractor.getCourseStructure(courseId) + courseStructure.blockData + .find { it.descendants.contains(componentId) }?.let { block -> + appRouter.navigateToCourseContainer( + fm = fm, + courseId = courseId, + unitId = block.id, + componentId = componentId, + mode = CourseViewMode.FULL + ) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + } + } + + private fun navigateToProgram(fm: FragmentManager, deepLink: DeepLink) { + val pathId = deepLink.pathId + if (pathId == null) { + navigateToPrograms(fm = fm) + } else { + appRouter.navigateToEnrolledProgramInfo( + fm = fm, + pathId = pathId + ) + } + } + + private fun navigateToDiscussionTopic(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + deepLink.topicId?.let { topicId -> + launch { + try { + discussionInteractor.getCourseTopics(courseId) + .find { it.id == topicId }?.let { topic -> + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionThread( + fm = fm, + action = DiscussionTopicsViewModel.TOPIC, + courseId = courseId, + topicId = topicId, + title = topic.name, + viewType = FragmentViewType.FULL_CONTENT + ) + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + } + } + + private fun navigateToDiscussionPost(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + deepLink.topicId?.let { topicId -> + deepLink.threadId?.let { threadId -> + launch { + try { + discussionInteractor.getCourseTopics(courseId) + .find { it.id == topicId }?.let { topic -> + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionThread( + fm = fm, + action = DiscussionTopicsViewModel.TOPIC, + courseId = courseId, + topicId = topicId, + title = topic.name, + viewType = FragmentViewType.FULL_CONTENT + ) + } + } + val thread = discussionInteractor.getThread( + threadId, + courseId, + topicId + ) + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionComments( + fm = fm, + thread = thread + ) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + } + } + } + + private fun navigateToDiscussionComment(fm: FragmentManager, deepLink: DeepLink) { + deepLink.courseId?.let { courseId -> + deepLink.topicId?.let { topicId -> + deepLink.threadId?.let { threadId -> + deepLink.commentId?.let { commentId -> + launch { + try { + discussionInteractor.getCourseTopics(courseId) + .find { it.id == topicId }?.let { topic -> + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionThread( + fm = fm, + action = DiscussionTopicsViewModel.TOPIC, + courseId = courseId, + topicId = topicId, + title = topic.name, + viewType = FragmentViewType.FULL_CONTENT + ) + } + } + val thread = discussionInteractor.getThread( + threadId, + courseId, + topicId + ) + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionComments( + fm = fm, + thread = thread + ) + } + val commentsData = discussionInteractor.getThreadComment(commentId) + commentsData.results.firstOrNull()?.let { comment -> + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionResponses( + fm = fm, + comment = comment, + isClosed = false + ) + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + } + } + } + } + + private fun navigateToDashboard(fm: FragmentManager) { + appRouter.navigateToMain( + fm = fm, + courseId = null, + infoType = null, + openTab = "LEARN" + ) + } + + private fun navigateToPrograms(fm: FragmentManager) { + appRouter.navigateToMain( + fm = fm, + courseId = null, + infoType = null, + openTab = "PROGRAMS" + ) + } + + private fun navigateToProfile(fm: FragmentManager) { + appRouter.navigateToMain( + fm = fm, + courseId = null, + infoType = null, + openTab = "PROFILE" + ) + } +} diff --git a/app/src/main/java/org/openedx/app/deeplink/HomeTab.kt b/app/src/main/java/org/openedx/app/deeplink/HomeTab.kt new file mode 100644 index 000000000..c020cf636 --- /dev/null +++ b/app/src/main/java/org/openedx/app/deeplink/HomeTab.kt @@ -0,0 +1,8 @@ +package org.openedx.app.deeplink + +enum class HomeTab { + LEARN, + PROGRAMS, + DISCOVER, + PROFILE +} diff --git a/app/src/main/java/org/openedx/app/deeplink/Screen.kt b/app/src/main/java/org/openedx/app/deeplink/Screen.kt new file mode 100644 index 000000000..e877649e8 --- /dev/null +++ b/app/src/main/java/org/openedx/app/deeplink/Screen.kt @@ -0,0 +1,20 @@ +package org.openedx.app.deeplink + +enum class Screen(val screenName: String) { + DISCOVERY("discovery"), + DISCOVERY_COURSE_DETAIL("discovery_course_detail"), + DISCOVERY_PROGRAM_DETAIL("discovery_program_detail"), + COURSE_DASHBOARD("course_dashboard"), + COURSE_VIDEOS("course_videos"), + COURSE_DISCUSSION("course_discussion"), + COURSE_DATES("course_dates"), + COURSE_HANDOUT("course_handout"), + COURSE_ANNOUNCEMENT("course_announcement"), + COURSE_COMPONENT("course_component"), + PROGRAM("program"), + DISCUSSION_TOPIC("discussion_topic"), + DISCUSSION_POST("discussion_post"), + DISCUSSION_COMMENT("discussion_comment"), + PROFILE("profile"), + USER_PROFILE("user_profile"), +} diff --git a/app/src/main/java/org/openedx/app/di/AppModule.kt b/app/src/main/java/org/openedx/app/di/AppModule.kt index a5ec76b37..1d1dc7e0c 100644 --- a/app/src/main/java/org/openedx/app/di/AppModule.kt +++ b/app/src/main/java/org/openedx/app/di/AppModule.kt @@ -12,6 +12,7 @@ import org.koin.core.qualifier.named import org.koin.dsl.module import org.openedx.app.AnalyticsManager import org.openedx.app.AppAnalytics +import org.openedx.app.deeplink.DeepLinkRouter import org.openedx.app.AppRouter import org.openedx.app.BuildConfig import org.openedx.app.data.storage.PreferencesManager @@ -109,6 +110,7 @@ val appModule = module { single { get() } single { get() } single { get() } + single { DeepLinkRouter(get(), get(), get(), get(), get()) } single { NetworkConnection(get()) } diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 393b16248..0c2c85474 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -67,7 +67,7 @@ import org.openedx.whatsnew.presentation.whatsnew.WhatsNewViewModel val screenModule = module { - viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get(), get()) } + viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get(), get(), get()) } viewModel { MainViewModel(get(), get(), get()) } factory { AuthRepository(get(), get(), get()) } diff --git a/app/src/test/java/org/openedx/AppViewModelTest.kt b/app/src/test/java/org/openedx/AppViewModelTest.kt index c81c9c2e5..35a2d3d96 100644 --- a/app/src/test/java/org/openedx/AppViewModelTest.kt +++ b/app/src/test/java/org/openedx/AppViewModelTest.kt @@ -21,6 +21,7 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TestRule import org.openedx.app.AppAnalytics +import org.openedx.app.deeplink.DeepLinkRouter import org.openedx.app.AppViewModel import org.openedx.app.data.storage.PreferencesManager import org.openedx.app.room.AppDatabase @@ -44,6 +45,7 @@ class AppViewModelTest { private val preferencesManager = mockk() private val analytics = mockk() private val fileUtil = mockk() + private val deepLinkRouter = mockk() private val user = User(0, "", "", "") @@ -71,6 +73,7 @@ class AppViewModelTest { preferencesManager, dispatcher, analytics, + deepLinkRouter, fileUtil ) @@ -102,6 +105,7 @@ class AppViewModelTest { preferencesManager, dispatcher, analytics, + deepLinkRouter, fileUtil ) @@ -135,6 +139,7 @@ class AppViewModelTest { preferencesManager, dispatcher, analytics, + deepLinkRouter, fileUtil ) diff --git a/auth/src/main/java/org/openedx/auth/presentation/AuthRouter.kt b/auth/src/main/java/org/openedx/auth/presentation/AuthRouter.kt index 9b1266119..945acf02e 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/AuthRouter.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/AuthRouter.kt @@ -4,7 +4,12 @@ import androidx.fragment.app.FragmentManager interface AuthRouter { - fun navigateToMain(fm: FragmentManager, courseId: String?, infoType: String?) + fun navigateToMain( + fm: FragmentManager, + courseId: String?, + infoType: String?, + openTab: String = "" + ) fun navigateToSignIn(fm: FragmentManager, courseId: String?, infoType: String?) diff --git a/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt b/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt index 9b34e7617..3b59be61d 100644 --- a/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt +++ b/course/src/main/java/org/openedx/course/presentation/CourseRouter.kt @@ -56,7 +56,7 @@ interface CourseRouter { ) fun navigateToHandoutsWebView( - fm: FragmentManager, courseId: String, title: String, type: HandoutsType + fm: FragmentManager, courseId: String, type: HandoutsType ) fun navigateToDownloadQueue(fm: FragmentManager, descendants: List = arrayListOf()) 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 4df1fcf64..49d6b8cae 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 @@ -140,7 +140,7 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { snackBar?.show() } - lifecycleScope.launch { + viewLifecycleOwner.lifecycleScope.launch { viewModel.showProgress.collect { binding.progressBar.isVisible = it } @@ -522,15 +522,12 @@ fun DashboardPager( } CourseContainerTab.MORE -> { - val announcementsString = stringResource(id = R.string.course_announcements) - val handoutsString = stringResource(id = R.string.course_handouts) HandoutsScreen( windowSize = windowSize, onHandoutsClick = { viewModel.courseRouter.navigateToHandoutsWebView( fragmentManager, bundle.getString(CourseContainerFragment.ARG_COURSE_ID, ""), - handoutsString, HandoutsType.Handouts ) }, @@ -538,7 +535,6 @@ fun DashboardPager( viewModel.courseRouter.navigateToHandoutsWebView( fragmentManager, bundle.getString(CourseContainerFragment.ARG_COURSE_ID, ""), - announcementsString, HandoutsType.Announcements ) }) diff --git a/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsWebViewFragment.kt b/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsWebViewFragment.kt index 7c9d3615e..16cc67b84 100644 --- a/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsWebViewFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsWebViewFragment.kt @@ -22,6 +22,7 @@ import org.openedx.core.ui.WindowType import org.openedx.core.ui.rememberWindowSize import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors +import org.openedx.course.R import org.openedx.course.presentation.CourseAnalyticsEvent class HandoutsWebViewFragment : Fragment() { @@ -39,6 +40,15 @@ class HandoutsWebViewFragment : Fragment() { savedInstanceState: Bundle?, ) = ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + + val title = if (HandoutsType.valueOf(viewModel.handoutsType) == HandoutsType.Handouts) { + viewModel.logEvent(CourseAnalyticsEvent.HANDOUTS) + getString(R.string.course_handouts) + } else { + viewModel.logEvent(CourseAnalyticsEvent.ANNOUNCEMENTS) + getString(R.string.course_announcements) + } + setContent { OpenEdXTheme { val windowSize = rememberWindowSize() @@ -50,7 +60,7 @@ class HandoutsWebViewFragment : Fragment() { WebContentScreen( windowSize = windowSize, apiHostUrl = viewModel.apiHostUrl, - title = requireArguments().getString(ARG_TITLE, ""), + title = title, htmlBody = viewModel.injectDarkMode( htmlBody, colorBackgroundValue, @@ -61,26 +71,18 @@ class HandoutsWebViewFragment : Fragment() { }) } } - if (HandoutsType.valueOf(viewModel.handoutsType) == HandoutsType.Handouts) { - viewModel.logEvent(CourseAnalyticsEvent.HANDOUTS) - } else { - viewModel.logEvent(CourseAnalyticsEvent.ANNOUNCEMENTS) - } } companion object { - private val ARG_TITLE = "argTitle" private val ARG_TYPE = "argType" private val ARG_COURSE_ID = "argCourse" fun newInstance( - title: String, type: String, courseId: String, ): HandoutsWebViewFragment { val fragment = HandoutsWebViewFragment() fragment.arguments = bundleOf( - ARG_TITLE to title, ARG_TYPE to type, ARG_COURSE_ID to courseId ) diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt index 7a79f3c2e..1fc574f41 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.viewpager2.widget.ViewPager2 @@ -64,15 +65,22 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + initViewPager() + val openTab = requireArguments().getString(ARG_OPEN_TAB, LearnTab.COURSES.name) + val defaultLearnType = if (openTab == LearnTab.PROGRAMS.name) { + LearnType.PROGRAMS + } else { + LearnType.COURSES + } binding.header.setContent { OpenEdXTheme { Header( fragmentManager = requireParentFragment().parentFragmentManager, + defaultLearnType = defaultLearnType, viewPager = binding.viewPager ) } } - initViewPager() } private fun initViewPager() { @@ -86,11 +94,25 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { binding.viewPager.adapter = adapter binding.viewPager.setUserInputEnabled(false) } + + companion object { + private const val ARG_OPEN_TAB = "open_tab" + fun newInstance( + openTab: String = LearnTab.COURSES.name + ): LearnFragment { + val fragment = LearnFragment() + fragment.arguments = bundleOf( + ARG_OPEN_TAB to openTab + ) + return fragment + } + } } @Composable private fun Header( fragmentManager: FragmentManager, + defaultLearnType: LearnType, viewPager: ViewPager2, ) { val viewModel: LearnViewModel = koinViewModel() @@ -123,6 +145,7 @@ private fun Header( modifier = Modifier .align(Alignment.Start) .padding(horizontal = 16.dp), + defaultLearnType = defaultLearnType, viewPager = viewPager ) } @@ -166,10 +189,11 @@ private fun Title( @Composable private fun LearnDropdownMenu( modifier: Modifier = Modifier, + defaultLearnType: LearnType, viewPager: ViewPager2, ) { var expanded by remember { mutableStateOf(false) } - var currentValue by remember { mutableStateOf(LearnType.COURSES) } + var currentValue by remember { mutableStateOf(defaultLearnType) } val iconRotation by animateFloatAsState( targetValue = if (expanded) 180f else 0f, label = "" @@ -270,6 +294,7 @@ private fun LearnDropdownMenuPreview() { OpenEdXTheme { val context = LocalContext.current LearnDropdownMenu( + defaultLearnType = LearnType.COURSES, viewPager = ViewPager2(context) ) } diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnTab.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnTab.kt new file mode 100644 index 000000000..c7498298a --- /dev/null +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnTab.kt @@ -0,0 +1,6 @@ +package org.openedx.learn.presentation + +enum class LearnTab { + COURSES, + PROGRAMS +} diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt b/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt index 0060199da..4c7eb1da6 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/detail/CourseDetailsFragment.kt @@ -164,7 +164,7 @@ class CourseDetailsFragment : Fragment() { requireActivity().supportFragmentManager, currentState.course.courseId, currentState.course.name, - "", + enrollmentMode = "" ) } diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt b/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt index 636cb9275..6d41ac4b1 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt @@ -122,7 +122,7 @@ class CourseInfoViewModel( fm = fragmentManager, courseId = courseId, courseTitle = "", - enrollmentMode = "", + enrollmentMode = "" ) } } diff --git a/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt b/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt index ebc911425..75a780d72 100644 --- a/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt +++ b/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt @@ -5,6 +5,7 @@ import org.openedx.discussion.data.model.request.* import org.openedx.discussion.data.model.response.CommentResult import org.openedx.discussion.data.model.response.CommentsResponse import org.openedx.discussion.data.model.response.ThreadsResponse +import org.openedx.discussion.data.model.response.ThreadsResponse.Thread import org.openedx.discussion.data.model.response.TopicsResponse import retrofit2.http.* @@ -26,6 +27,14 @@ interface DiscussionApi { @Query("requested_fields") requestedFields: List = listOf("profile_image") ): ThreadsResponse + @GET("/api/discussion/v1/threads/{thread_id}") + suspend fun getCourseThread( + @Path("thread_id") threadId: String, + @Query("course_id") courseId: String, + @Query("topic_id") topicId: String, + @Query("requested_fields") requestedFields: List = listOf("profile_image") + ): Thread + @GET("/api/discussion/v1/threads/") suspend fun searchThreads( @Query("course_id") courseId: String, @@ -41,6 +50,12 @@ interface DiscussionApi { @Query("requested_fields") requestedFields: List = listOf("profile_image") ): CommentsResponse + @GET("/api/discussion/v1/comments/{comment_id}") + suspend fun getThreadComment( + @Path("comment_id") commentId: String, + @Query("requested_fields") requestedFields: List = listOf("profile_image") + ): CommentsResponse + @GET("/api/discussion/v1/comments/") suspend fun getThreadQuestionComments( @Query("thread_id") threadId: String, diff --git a/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt b/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt index 4ca6cde8d..3ee4f74a5 100644 --- a/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt +++ b/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt @@ -58,6 +58,14 @@ class DiscussionRepository( return api.getCourseThreads(courseId, following, topicId, orderBy, view, page).mapToDomain() } + suspend fun getCourseThread( + threadId: String, + courseId: String, + topicId: String + ): org.openedx.discussion.domain.model.Thread { + return api.getCourseThread(threadId, courseId, topicId).mapToDomain() + } + suspend fun searchThread( courseId: String, query: String, @@ -73,6 +81,12 @@ class DiscussionRepository( return api.getThreadComments(threadId, page).mapToDomain() } + suspend fun getThreadComment( + commentId: String + ): CommentsData { + return api.getThreadComment(commentId).mapToDomain() + } + suspend fun getThreadQuestionComments( threadId: String, endorsed: Boolean, @@ -142,4 +156,4 @@ class DiscussionRepository( return api.markBlocksCompletion(blocksCompletionBody) } -} \ No newline at end of file +} diff --git a/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt b/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt index 7225cc443..561a75006 100644 --- a/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt +++ b/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt @@ -1,6 +1,7 @@ package org.openedx.discussion.domain.interactor import org.openedx.discussion.data.repository.DiscussionRepository +import org.openedx.discussion.domain.model.CommentsData class DiscussionInteractor( private val repository: DiscussionRepository @@ -31,12 +32,18 @@ class DiscussionInteractor( ) = repository.getCourseThreads(courseId, null, topicId, orderBy, view, page) + suspend fun getThread(threadId: String, courseId: String, topicId: String) = + repository.getCourseThread(threadId, courseId, topicId) + suspend fun searchThread(courseId: String, query: String, page: Int) = repository.searchThread(courseId, query, page) suspend fun getThreadComments(threadId: String, page: Int) = repository.getThreadComments(threadId, page) + suspend fun getThreadComment(commentId: String): CommentsData = + repository.getThreadComment(commentId) + suspend fun getThreadQuestionComments(threadId: String, endorsed: Boolean, page: Int) = repository.getThreadQuestionComments(threadId, endorsed, page) @@ -87,5 +94,6 @@ class DiscussionInteractor( follow: Boolean ) = repository.createThread(topicId, courseId, type, title, rawBody, follow) - suspend fun markBlocksCompletion(courseId: String, blocksId: List) = repository.markBlocksCompletion(courseId, blocksId) -} \ No newline at end of file + suspend fun markBlocksCompletion(courseId: String, blocksId: List) = + repository.markBlocksCompletion(courseId, blocksId) +} diff --git a/whatsnew/src/main/java/org/openedx/whatsnew/WhatsNewRouter.kt b/whatsnew/src/main/java/org/openedx/whatsnew/WhatsNewRouter.kt index a8d1cd463..82d02f000 100644 --- a/whatsnew/src/main/java/org/openedx/whatsnew/WhatsNewRouter.kt +++ b/whatsnew/src/main/java/org/openedx/whatsnew/WhatsNewRouter.kt @@ -3,5 +3,10 @@ package org.openedx.whatsnew import androidx.fragment.app.FragmentManager interface WhatsNewRouter { - fun navigateToMain(fm: FragmentManager, courseId: String? = null, infoType: String? = null) + fun navigateToMain( + fm: FragmentManager, + courseId: String?, + infoType: String?, + openTab: String + ) } diff --git a/whatsnew/src/main/java/org/openedx/whatsnew/presentation/whatsnew/WhatsNewViewModel.kt b/whatsnew/src/main/java/org/openedx/whatsnew/presentation/whatsnew/WhatsNewViewModel.kt index 51f0f9646..534a54f13 100644 --- a/whatsnew/src/main/java/org/openedx/whatsnew/presentation/whatsnew/WhatsNewViewModel.kt +++ b/whatsnew/src/main/java/org/openedx/whatsnew/presentation/whatsnew/WhatsNewViewModel.kt @@ -41,7 +41,8 @@ class WhatsNewViewModel( router.navigateToMain( fm, courseId, - infoType + infoType, + "" ) } From 5c887eb4910614f6a589923ab3a5c4949c773c0b Mon Sep 17 00:00:00 2001 From: Hamza Israr <71447999+HamzaIsrar12@users.noreply.github.com> Date: Tue, 11 Jun 2024 18:10:04 +0500 Subject: [PATCH 17/38] fix: UI Issues on Auth Screens (#332) - feat: Add password visibility toggle to the password fields - fix: Autofill the "Full Name" and "Email" fields with SSO data - refactor: Redesign the modal that appears after SSO Fixes: Issue#331 --- .../presentation/signin/compose/SignInView.kt | 19 +++++-- .../presentation/signup/SignUpViewModel.kt | 11 ++-- .../presentation/signup/compose/SignUpView.kt | 4 +- .../signup/compose/SocialSignedView.kt | 37 +++++++++---- .../openedx/auth/presentation/ui/AuthUI.kt | 54 +++++++++++++++++-- auth/src/main/res/values/strings.xml | 2 + .../org/openedx/core/ui/theme/AppColors.kt | 2 + .../java/org/openedx/core/ui/theme/Theme.kt | 4 ++ .../src/main/res/drawable/ic_core_check.xml | 0 .../org/openedx/core/ui/theme/Colors.kt | 4 ++ .../course/presentation/ui/CourseUI.kt | 2 +- 11 files changed, 116 insertions(+), 23 deletions(-) rename course/src/main/res/drawable/ic_course_check.xml => core/src/main/res/drawable/ic_core_check.xml (100%) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index 37309cadf..783a60a99 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview @@ -58,6 +59,7 @@ import org.openedx.auth.R import org.openedx.auth.presentation.signin.AuthEvent import org.openedx.auth.presentation.signin.SignInUIState import org.openedx.auth.presentation.ui.LoginTextField +import org.openedx.auth.presentation.ui.PasswordVisibilityIcon import org.openedx.auth.presentation.ui.SocialAuthView import org.openedx.core.UIMessage import org.openedx.core.extension.TextConverter @@ -305,11 +307,11 @@ private fun PasswordTextField( onPressDone: () -> Unit, ) { var passwordTextFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf( - TextFieldValue("") - ) + mutableStateOf(TextFieldValue("")) } + var isPasswordVisible by remember { mutableStateOf(false) } val focusManager = LocalFocusManager.current + Text( modifier = Modifier .testTag("txt_password_label") @@ -318,7 +320,9 @@ private fun PasswordTextField( color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.labelLarge ) + Spacer(modifier = Modifier.height(8.dp)) + OutlinedTextField( modifier = modifier.testTag("tf_password"), value = passwordTextFieldValue, @@ -341,11 +345,18 @@ private fun PasswordTextField( style = MaterialTheme.appTypography.bodyMedium ) }, + trailingIcon = { + PasswordVisibilityIcon( + isPasswordVisible = isPasswordVisible, + onClick = { isPasswordVisible = !isPasswordVisible } + ) + }, keyboardOptions = KeyboardOptions.Default.copy( keyboardType = KeyboardType.Password, imeAction = ImeAction.Done ), - visualTransformation = PasswordVisualTransformation(), + visualTransformation = if (isPasswordVisible) VisualTransformation.None + else PasswordVisualTransformation(), keyboardActions = KeyboardActions { focusManager.clearFocus() onPressDone() diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt index 8fafe40ff..08bbce466 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt @@ -226,9 +226,14 @@ class SignUpViewModel( interactor.loginSocial(socialAuth.accessToken, socialAuth.authType) }.onFailure { val fields = uiState.value.allFields.toMutableList() - .filter { field -> field.type != RegistrationFieldType.PASSWORD } - updateField(ApiConstants.NAME, socialAuth.name) - updateField(ApiConstants.EMAIL, socialAuth.email) + .filter { it.type != RegistrationFieldType.PASSWORD } + .map { field -> + when (field.name) { + ApiConstants.NAME -> field.copy(placeholder = socialAuth.name) + ApiConstants.EMAIL -> field.copy(placeholder = socialAuth.email) + else -> field + } + } setErrorInstructions(emptyMap()) _uiState.update { it.copy( diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt index 42fd894df..2872c579b 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Devices @@ -317,10 +318,11 @@ internal fun SignUpView( Text( modifier = Modifier .fillMaxWidth() - .padding(top = 4.dp), + .padding(top = 8.dp), text = stringResource( id = R.string.auth_compete_registration ), + fontWeight = FontWeight.Bold, color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.titleSmall ) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt index 25a9434d1..b2dee1919 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt @@ -3,11 +3,15 @@ package org.openedx.auth.presentation.signup.compose import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Devices @@ -26,21 +30,36 @@ internal fun SocialSignedView(authType: AuthType) { Column( modifier = Modifier .background( - color = MaterialTheme.appColors.secondary, + color = MaterialTheme.appColors.authSSOSuccessBackground, shape = MaterialTheme.appShapes.buttonShape ) .padding(20.dp) ) { - Text( - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - text = stringResource( - id = R.string.auth_social_signed_title, - authType.methodName + Row { + Icon( + modifier = Modifier + .padding(end = 8.dp) + .size(20.dp), + painter = painterResource(id = coreR.drawable.ic_core_check), + tint = MaterialTheme.appColors.successBackground, + contentDescription = "" ) - ) + + Text( + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colors.primary, + text = stringResource( + id = R.string.auth_social_signed_title, + authType.methodName + ) + ) + } + Text( - modifier = Modifier.padding(top = 8.dp), + modifier = Modifier.padding(top = 8.dp, start = 28.dp), + fontSize = 14.sp, + fontWeight = FontWeight.Normal, text = stringResource( id = R.string.auth_social_signed_desc, stringResource(id = coreR.string.app_name) diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt index 90fb91ee1..16d75492b 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedTextField import androidx.compose.material.Text @@ -23,6 +24,8 @@ import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.ExpandMore +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -70,7 +73,10 @@ fun RequiredFields( ) { fields.forEach { field -> when (field.type) { - RegistrationFieldType.TEXT, RegistrationFieldType.EMAIL, RegistrationFieldType.CONFIRM_EMAIL, RegistrationFieldType.PASSWORD -> { + RegistrationFieldType.TEXT, + RegistrationFieldType.EMAIL, + RegistrationFieldType.CONFIRM_EMAIL, + RegistrationFieldType.PASSWORD -> { InputRegistrationField( modifier = Modifier.fillMaxWidth(), isErrorShown = showErrorMap[field.name] ?: true, @@ -289,11 +295,15 @@ fun InputRegistrationField( var inputRegistrationFieldValue by rememberSaveable { mutableStateOf(registrationField.placeholder) } + var isPasswordVisible by remember { mutableStateOf(false) } + val focusManager = LocalFocusManager.current - val visualTransformation = if (registrationField.type == RegistrationFieldType.PASSWORD) { - PasswordVisualTransformation() - } else { - VisualTransformation.None + val visualTransformation = remember(isPasswordVisible) { + if (registrationField.type == RegistrationFieldType.PASSWORD && !isPasswordVisible) { + PasswordVisualTransformation() + } else { + VisualTransformation.None + } } val keyboardType = when (registrationField.type) { RegistrationFieldType.CONFIRM_EMAIL, RegistrationFieldType.EMAIL -> KeyboardType.Email @@ -315,6 +325,18 @@ fun InputRegistrationField( } else { registrationField.instructions } + val trailingIcon: @Composable (() -> Unit)? = + if (registrationField.type == RegistrationFieldType.PASSWORD) { + { + PasswordVisibilityIcon( + isPasswordVisible = isPasswordVisible, + onClick = { isPasswordVisible = !isPasswordVisible } + ) + } + } else { + null + } + Column { Text( modifier = Modifier @@ -359,6 +381,7 @@ fun InputRegistrationField( keyboardActions = KeyboardActions { focusManager.moveFocus(FocusDirection.Down) }, + trailingIcon = trailingIcon, textStyle = MaterialTheme.appTypography.bodyMedium, singleLine = isSingleLine, modifier = modifier.testTag("tf_${registrationField.name.tagId()}") @@ -418,6 +441,7 @@ fun SelectableRegisterField( OutlinedTextField( readOnly = true, enabled = false, + singleLine = true, value = initialValue, colors = TextFieldDefaults.outlinedTextFieldColors( unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, @@ -510,6 +534,26 @@ fun ExpandableText( } } +@Composable +internal fun PasswordVisibilityIcon( + isPasswordVisible: Boolean, + onClick: () -> Unit +) { + val (image, description) = if (isPasswordVisible) { + Icons.Filled.VisibilityOff to stringResource(R.string.auth_accessibility_hide_password) + } else { + Icons.Filled.Visibility to stringResource(R.string.auth_accessibility_show_password) + } + + IconButton(onClick = onClick) { + Icon( + imageVector = image, + contentDescription = description, + tint = MaterialTheme.appColors.onSurface + ) + } +} + @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 49b3e0bbd..642185915 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -39,4 +39,6 @@ By creating an account, you agree to the %1$s and %2$s and you acknowledge that %3$s and each Member process your personal data in accordance with the %4$s. By signing in to this app, you agree to the %1$s and %2$s and you acknowledge that %3$s and each Member process your personal data in accordance with the %4$s. %2$s]]> + Show password + Hide password diff --git a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt index 625c52b27..37783b820 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt @@ -51,6 +51,7 @@ data class AppColors( val inactiveButtonText: Color, val successGreen: Color, + val successBackground: Color, val datesSectionBarPastDue: Color, val datesSectionBarToday: Color, @@ -58,6 +59,7 @@ data class AppColors( val datesSectionBarNextWeek: Color, val datesSectionBarUpcoming: Color, + val authSSOSuccessBackground: Color, val authGoogleButtonBackground: Color, val authFacebookButtonBackground: Color, val authMicrosoftButtonBackground: Color, diff --git a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt index 88c973105..8fe1eb8ff 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt @@ -69,6 +69,7 @@ private val DarkColorPalette = AppColors( inactiveButtonText = dark_primary_button_text, successGreen = dark_success_green, + successBackground = dark_success_background, datesSectionBarPastDue = dark_dates_section_bar_past_due, datesSectionBarToday = dark_dates_section_bar_today, @@ -76,6 +77,7 @@ private val DarkColorPalette = AppColors( datesSectionBarNextWeek = dark_dates_section_bar_next_week, datesSectionBarUpcoming = dark_dates_section_bar_upcoming, + authSSOSuccessBackground = dark_auth_sso_success_background, authGoogleButtonBackground = dark_auth_google_button_background, authFacebookButtonBackground = dark_auth_facebook_button_background, authMicrosoftButtonBackground = dark_auth_microsoft_button_background, @@ -156,6 +158,7 @@ private val LightColorPalette = AppColors( inactiveButtonText = light_primary_button_text, successGreen = light_success_green, + successBackground = light_success_background, datesSectionBarPastDue = light_dates_section_bar_past_due, datesSectionBarToday = light_dates_section_bar_today, @@ -163,6 +166,7 @@ private val LightColorPalette = AppColors( datesSectionBarNextWeek = light_dates_section_bar_next_week, datesSectionBarUpcoming = light_dates_section_bar_upcoming, + authSSOSuccessBackground = light_auth_sso_success_background, authGoogleButtonBackground = light_auth_google_button_background, authFacebookButtonBackground = light_auth_facebook_button_background, authMicrosoftButtonBackground = light_auth_microsoft_button_background, diff --git a/course/src/main/res/drawable/ic_course_check.xml b/core/src/main/res/drawable/ic_core_check.xml similarity index 100% rename from course/src/main/res/drawable/ic_course_check.xml rename to core/src/main/res/drawable/ic_core_check.xml diff --git a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt index 855d557d3..ffc0b64e2 100644 --- a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt @@ -52,11 +52,13 @@ val light_info = Color(0xFF42AAFF) val light_rate_stars = Color(0xFFFFC94D) val light_inactive_button_background = Color(0xFFCCD4E0) val light_success_green = Color(0xFF198571) +val light_success_background = Color(0xFF0D7D4D) val light_dates_section_bar_past_due = light_warning val light_dates_section_bar_today = light_info val light_dates_section_bar_this_week = light_text_primary_variant val light_dates_section_bar_next_week = light_text_field_border val light_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val light_auth_sso_success_background = light_secondary val light_auth_google_button_background = Color.White val light_auth_facebook_button_background = Color(0xFF0866FF) val light_auth_microsoft_button_background = Color(0xFA000000) @@ -124,11 +126,13 @@ val dark_onInfo = Color.White val dark_rate_stars = Color(0xFFFFC94D) val dark_inactive_button_background = Color(0xFFCCD4E0) val dark_success_green = Color(0xFF198571) +val dark_success_background = Color.White val dark_dates_section_bar_past_due = dark_warning val dark_dates_section_bar_today = dark_info val dark_dates_section_bar_this_week = dark_text_primary_variant val dark_dates_section_bar_next_week = dark_text_field_border val dark_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val dark_auth_sso_success_background = dark_secondary val dark_auth_google_button_background = Color(0xFF19212F) val dark_auth_facebook_button_background = Color(0xFF0866FF) val dark_auth_microsoft_button_background = Color(0xFA000000) 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 7d8729fac..c187af0ad 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 @@ -911,7 +911,7 @@ fun SubSectionUnitsList( modifier = Modifier .size(16.dp) .alpha(if (unit.isCompleted()) 1f else 0f), - painter = painterResource(id = R.drawable.ic_course_check), + painter = painterResource(id = coreR.drawable.ic_core_check), contentDescription = "done" ) Text( From efd39981c3135a883fff471b9b7e8104cc501ed1 Mon Sep 17 00:00:00 2001 From: Hamza Israr <71447999+HamzaIsrar12@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:24:04 +0500 Subject: [PATCH 18/38] feat: Add Branch deep links to local calendar events (#249) - Add branch deep links to Calendar Events - Resolved Calendar Dialogs Issue Caused by Permission Launcher Fixes: LEARNER-9795 --- app/build.gradle | 5 ---- core/build.gradle | 5 ++++ .../calendarsync/CalendarSyncUIState.kt | 5 +++- .../openedx/core/system/CalendarManager.kt | 25 +++++++++++-------- .../container/CourseContainerViewModel.kt | 4 +++ 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 86363a2b7..f949e477f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -141,11 +141,6 @@ dependencies { // Firebase Cloud Messaging Integration for Braze implementation 'com.google.firebase:firebase-messaging-ktx:23.4.1' - // Branch SDK Integration - implementation 'io.branch.sdk.android:library:5.9.0' - implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' - implementation "com.android.installreferrer:installreferrer:2.2" - androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" diff --git a/core/build.gradle b/core/build.gradle index f5dc7841f..2360efd4d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -156,6 +156,11 @@ dependencies { api "androidx.webkit:webkit:$webkit_version" + // Branch SDK Integration + api "io.branch.sdk.android:library:5.9.0" + api "com.google.android.gms:play-services-ads-identifier:18.0.1" + api "com.android.installreferrer:installreferrer:2.2" + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncUIState.kt b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncUIState.kt index e3062d970..1f32f3f56 100644 --- a/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncUIState.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/calendarsync/CalendarSyncUIState.kt @@ -11,4 +11,7 @@ data class CalendarSyncUIState( val isSynced: Boolean = false, val checkForOutOfSync: AtomicReference = AtomicReference(false), val uiMessage: AtomicReference = AtomicReference(""), -) +) { + val isDialogVisible: Boolean + get() = dialogType != CalendarSyncDialogType.NONE +} diff --git a/core/src/main/java/org/openedx/core/system/CalendarManager.kt b/core/src/main/java/org/openedx/core/system/CalendarManager.kt index 53d7a1e1f..e1e6f926d 100644 --- a/core/src/main/java/org/openedx/core/system/CalendarManager.kt +++ b/core/src/main/java/org/openedx/core/system/CalendarManager.kt @@ -10,6 +10,9 @@ import android.database.Cursor import android.net.Uri import android.provider.CalendarContract import androidx.core.content.ContextCompat +import io.branch.indexing.BranchUniversalObject +import io.branch.referral.util.ContentMetadata +import io.branch.referral.util.LinkProperties import org.openedx.core.R import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.CourseDateBlock @@ -94,7 +97,7 @@ class CalendarManager( contentValues.put(CalendarContract.Calendars.VISIBLE, 1) contentValues.put( CalendarContract.Calendars.CALENDAR_COLOR, - ContextCompat.getColor(context, org.openedx.core.R.color.primary) + ContextCompat.getColor(context, R.color.primary) ) val creationUri: Uri? = asSyncAdapter( Uri.parse(CalendarContract.Calendars.CONTENT_URI.toString()), @@ -191,17 +194,16 @@ class CalendarManager( courseDateBlock: CourseDateBlock, isDeeplinkEnabled: Boolean ): String { - val eventDescription = courseDateBlock.title - // The following code for branch and deep links will be enabled after implementation - /* - if (isDeeplinkEnabled && !TextUtils.isEmpty(courseDateBlock.blockId)) { + var eventDescription = courseDateBlock.title + + if (isDeeplinkEnabled && courseDateBlock.blockId.isNotEmpty()) { val metaData = ContentMetadata() - .addCustomMetadata(DeepLink.Keys.SCREEN_NAME, Screen.COURSE_COMPONENT) - .addCustomMetadata(DeepLink.Keys.COURSE_ID, courseId) - .addCustomMetadata(DeepLink.Keys.COMPONENT_ID, courseDateBlock.blockId) + .addCustomMetadata("screen_name", "course_component") + .addCustomMetadata("course_id", courseId) + .addCustomMetadata("component_id", courseDateBlock.blockId) val branchUniversalObject = BranchUniversalObject() - .setCanonicalIdentifier("${Screen.COURSE_COMPONENT}\n${courseDateBlock.blockId}") + .setCanonicalIdentifier("course_component\n${courseDateBlock.blockId}") .setTitle(courseDateBlock.title) .setContentDescription(courseDateBlock.title) .setContentMetadata(metaData) @@ -209,9 +211,10 @@ class CalendarManager( val linkProperties = LinkProperties() .addControlParameter("\$desktop_url", courseDateBlock.link) - eventDescription += "\n" + branchUniversalObject.getShortUrl(context, linkProperties) + val shortUrl = branchUniversalObject.getShortUrl(context, linkProperties) + eventDescription += "\n$shortUrl" } - */ + return eventDescription } 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 4e233e3d7..97045561e 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 @@ -135,6 +135,10 @@ class CourseContainerViewModel( } is CreateCalendarSyncEvent -> { + // Skip out-of-sync check if any calendar dialog is visible + if (event.checkOutOfSync && _calendarSyncUIState.value.isDialogVisible) { + return@collect + } _calendarSyncUIState.update { val dialogType = CalendarSyncDialogType.valueOf(event.dialogType) it.copy( From 065d5830e8b96b8edd1e0a1953ca2a688958cd2d Mon Sep 17 00:00:00 2001 From: Amr Nashawaty Date: Wed, 12 Jun 2024 22:24:36 +0300 Subject: [PATCH 19/38] feat: atlas push pull scripts: FC-55 (#317) --- .gitignore | 3 + Makefile | 12 + README.md | 41 ++++ i18n_scripts/requirements.txt | 2 + i18n_scripts/translation.py | 431 ++++++++++++++++++++++++++++++++++ 5 files changed, 489 insertions(+) create mode 100644 Makefile create mode 100644 i18n_scripts/requirements.txt create mode 100644 i18n_scripts/translation.py diff --git a/.gitignore b/.gitignore index 1cc8ec083..1152644c7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ local.properties /.idea/ *.log /config_settings.yaml +.venv/ +i18n/ +**/values-*/strings.xml diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..e7ff3745b --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +clean_translations_temp_directory: + rm -rf i18n/ + +translation_requirements: + pip3 install -r i18n_scripts/requirements.txt + +pull_translations: clean_translations_temp_directory + atlas pull $(ATLAS_OPTIONS) translations/openedx-app-android/i18n:i18n + python3 i18n_scripts/translation.py --split --replace-underscore + +extract_translations: clean_translations_temp_directory + python3 i18n_scripts/translation.py --combine diff --git a/README.md b/README.md index c8453877a..65a19cce7 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,47 @@ Modern vision of the mobile application for the Open edX platform from Raccoon G 6. Click the **Run** button. +## Translations + +### Getting Translations for the App +Translations aren't included in the source code of this repository as of [OEP-58](https://docs.openedx.org/en/latest/developers/concepts/oep58.html). Therefore, they need to be pulled before testing or publishing to App Store. + +Before retrieving the translations for the app, we need to install the requirements listed in the requirements.txt file located in the i18n_scripts directory. This can be done easily by running the following make command: +```bash +make translation_requirements +``` + +Then, to get the latest translations for all languages use the following command: +```bash +make pull_translations +``` +This command runs [`atlas pull`](https://github.com/openedx/openedx-atlas) to download the latest translations files from the [openedx/openedx-translations](https://github.com/openedx/openedx-translations) repository. These files contain the latest translations for all languages. In the [openedx/openedx-translations](https://github.com/openedx/openedx-translations) repository each language's translations are saved as a single file e.g. `i18n/src/main/res/values-uk/strings.xml` ([example](https://github.com/openedx/openedx-translations/blob/04ccea36b8e6a9889646dfb5a5acb99686fa9ae0/translations/openedx-app-android/i18n/src/main/res/values-uk/strings.xml)). After these are pulled, each language's translation file is split into the App's modules e.g. `auth/src/main/res/values-uk/strings.xml`. + + After this command is run the application can load the translations by changing the device (or the emulator) language in the settings. + +### Using Custom Translations + +By default, the command `make pull_translations` runs [`atlas pull`](https://github.com/openedx/openedx-atlas) with no arguments which pulls translations from the [openedx-translations repository](https://github.com/openedx/openedx-translations). + +You can use custom translations on your fork of the openedx-translations repository by setting the following configuration parameters: + +- `--revision` (default: `"main"`): Branch or git tag to pull translations from. +- `--repository` (default: `"openedx/openedx-translations"`): GitHub repository slug. There's a feature request to [support GitLab and other providers](https://github.com/openedx/openedx-atlas/issues/20). + +Arguments can be passed via the `ATLAS_OPTIONS` environment variable as shown below: +``` bash +make ATLAS_OPTIONS='--repository=/ --revision=' pull_translations +``` +Additional arguments can be passed to `atlas pull`. Refer to the [atlas documentations ](https://github.com/openedx/openedx-atlas) for more information. + +### How to Translate the App + +Translations are managed in the [open-edx/openedx-translations](https://app.transifex.com/open-edx/openedx-translations/dashboard/) Transifex project. + +To translate the app join the [Transifex project](https://app.transifex.com/open-edx/openedx-translations/dashboard/) and add your translations `openedx-app-android` resource: https://app.transifex.com/open-edx/openedx-translations/openedx-app-android/ (the link will start working after the [pull request #317](https://github.com/openedx/openedx-app-android/pull/317) is merged) + +Once the resource is both 100% translated and reviewed the [Transifex integration](https://github.com/apps/transifex-integration) will automatically push it to the [openedx-translations](https://github.com/openedx/openedx-translations) repository and developers can use the translations in their app. + ## API This project targets on the latest Open edX release and rely on the relevant mobile APIs. diff --git a/i18n_scripts/requirements.txt b/i18n_scripts/requirements.txt new file mode 100644 index 000000000..918b88814 --- /dev/null +++ b/i18n_scripts/requirements.txt @@ -0,0 +1,2 @@ +openedx-atlas==0.6.1 +lxml==5.2.2 diff --git a/i18n_scripts/translation.py b/i18n_scripts/translation.py new file mode 100644 index 000000000..a21aa9eb5 --- /dev/null +++ b/i18n_scripts/translation.py @@ -0,0 +1,431 @@ +#!/usr/bin/env python3 +""" +# Translation Management Script + +This script is designed to manage translations for a project by performing two operations: +1) Getting the English translations from all modules. +2) Splitting translations into separate files for each module and language into a single file. + +More detailed specifications are described in the docs/0002-atlas-translations-management.rst design doc. +""" +import argparse +import os +import re +import sys +from lxml import etree + + +def parse_arguments(): + """ + This function is the argument parser for this script. + The script takes only one of the two arguments --split or --combine. + Additionally, the --replace-underscore argument can only be used with --split. + """ + parser = argparse.ArgumentParser(description='Split or Combine translations.') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--split', action='store_true', + help='Split translations into separate files for each module and language.') + group.add_argument('--combine', action='store_true', + help='Combine the English translations from all modules into a single file.') + parser.add_argument('--replace-underscore', action='store_true', + help='Replace underscores with "-r" in language directories (only with --split).') + return parser.parse_args() + + +def append_element_and_comment(element, previous_element, root): + """ + Appends the given element to the root XML element, preserving the previous element's comment if exists. + + Args: + element (etree.Element): The XML element to append. + previous_element (etree.Element or None): The previous XML element before the current one. + root (etree.Element): The root XML element to append the new element to. + + Returns: + None + """ + try: + # If there was a comment before the current element, add it first. + if isinstance(previous_element, etree._Comment): + previous_element.tail = '\n\t' + root.append(previous_element) + + # Indent all elements with one tab. + element.tail = '\n\t' + root.append(element) + + except Exception as e: + print(f"Error appending element and comment: {e}", file=sys.stderr) + raise + + +def get_translation_file_path(modules_dir, module_name, lang_dir, create_dirs=False): + """ + Retrieves the path of the translation file for a specified module and language directory. + + Parameters: + modules_dir (str): The path to the base directory containing all the modules. + module_name (str): The name of the module for which the translation path is being retrieved. + lang_dir (str): The name of the language directory within the module's directory. + create_dirs (bool): If True, creates the parent directories if they do not exist. Defaults to False. + + Returns: + str: The path to the module's translation file (Localizable.strings). + """ + try: + lang_dir_path = os.path.join(modules_dir, module_name, 'src', 'main', 'res', lang_dir, 'strings.xml') + if create_dirs: + os.makedirs(os.path.dirname(lang_dir_path), exist_ok=True) + return lang_dir_path + except Exception as e: + print(f"Error creating directory path: {e}", file=sys.stderr) + raise + + +def write_translation_file(modules_dir, root, module, lang_dir): + """ + Writes the XML root element to a strings.xml file in the specified language directory. + + Args: + modules_dir (str): The root directory of the project. + root (etree.Element): The root XML element to be written. + module (str): The name of the module. + lang_dir (str): The language directory to write the XML file to. + + Returns: + None + """ + try: + translation_file_path = get_translation_file_path(modules_dir, module, lang_dir, create_dirs=True) + tree = etree.ElementTree(root) + tree.write(translation_file_path, encoding='utf-8', xml_declaration=True) + except Exception as e: + print(f"Error writing translations to file.\n Module: {module}\n Error: {e}", file=sys.stderr) + raise + + +def get_modules_to_translate(modules_dir): + """ + Retrieve the names of modules that have translation files for a specified language. + + Parameters: + modules_dir (str): The path to the directory containing all the modules. + + Returns: + list of str: A list of module names that have translation files for the specified language. + """ + try: + modules_list = [ + directory for directory in os.listdir(modules_dir) + if ( + os.path.isdir(os.path.join(modules_dir, directory)) + and os.path.isfile(get_translation_file_path(modules_dir, directory, 'values')) + and directory != 'i18n' + ) + ] + return modules_list + except FileNotFoundError as e: + print(f"Directory not found: {e}", file=sys.stderr) + raise + except PermissionError as e: + print(f"Permission denied: {e}", file=sys.stderr) + raise + + +def process_module_translations(module_root, combined_root, module): + """ + Process translations from a module and append them to the combined translations. + + Parameters: + module_root (etree.Element): The root element of the module's translations. + combined_root (etree.Element): The combined translations root element. + module (str): The name of the module. + + Returns: + etree.Element: The updated combined translations root element. + """ + previous_element = None + for idx, element in enumerate(module_root.getchildren(), start=1): + try: + try: + translatable = element.attrib.get('translatable', True) + except KeyError as e: + print(f"Error processing element #{idx} from module {module}: " + f"Missing key 'translatable' in element attributes: {e}", file=sys.stderr) + raise + except Exception as e: + print(f"Error processing element #{idx} from module {module}: " + f"Unexpected error accessing 'translatable' attribute: {e}", file=sys.stderr) + raise + + if ( + translatable and translatable != 'false' # Check for the translatable property. + and element.tag in ['string', 'string-array', 'plurals'] # Only those types are read by transifex. + and (not element.nsmap + or element.nsmap and not element.attrib.get('{%s}ignore' % element.nsmap["tools"])) + ): + try: + element.attrib['name'] = '.'.join([module, element.attrib.get('name')]) + except KeyError as e: + print(f"Error setting attribute 'name' for element #{idx} from module {module}: Missing key 'name':" + f" {e}", file=sys.stderr) + raise + except Exception as e: + print(f"Error setting attribute 'name' for element #{idx} from module {module}: Unexpected error:" + f" {e}", file=sys.stderr) + raise + + try: + append_element_and_comment(element, previous_element, combined_root) + except Exception as e: + print(f"Error appending element #{idx} and comment from module {module}: {e}", file=sys.stderr) + raise + + # To check for comments in the next round. + previous_element = element + + except Exception as e: + print(f"Error processing element #{idx} from module {module}: {e}", file=sys.stderr) + raise + + return combined_root + + +def combine_translations(modules_dir): + """ + Combine translations from all specified modules into a single XML element. + + Parameters: + modules_dir (str): The directory containing the modules. + + Returns: + etree.Element: An XML element representing the combined translations. + """ + try: + combined_root = etree.Element('resources') + combined_root.text = '\n\t' + + modules = get_modules_to_translate(modules_dir) + for module in modules: + try: + translation_file = get_translation_file_path(modules_dir, module, 'values') + module_translations_tree = etree.parse(translation_file) + module_root = module_translations_tree.getroot() + combined_root = process_module_translations(module_root, combined_root, module) + + # Put a new line after each module translations. + if len(combined_root): + combined_root[-1].tail = '\n\n\t' + + except etree.XMLSyntaxError as e: + print(f"Error parsing XML file {translation_file}: {e}", file=sys.stderr) + raise + except FileNotFoundError as e: + print(f"Translation file not found: {e}", file=sys.stderr) + raise + except Exception as e: + print(f"Error processing module '{module}': {e}", file=sys.stderr) + raise + + # Unindent the resources closing tag. + if len(combined_root): + combined_root[-1].tail = '\n' + return combined_root + + except Exception as e: + print(f"Error combining translations: {e}", file=sys.stderr) + raise + + +def combine_translation_files(modules_dir=None): + """ + Combine translation files from different modules into a single file. + """ + try: + if not modules_dir: + modules_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + combined_root_element = combine_translations(modules_dir) + write_translation_file(modules_dir, combined_root_element, 'i18n', 'values') + except Exception as e: + print(f"Error combining translation files: {e}", file=sys.stderr) + raise + + +def get_languages_dirs(modules_dir): + """ + Retrieve directories containing language files for translation. + + Args: + modules_dir (str): The directory containing all the modules. + + Returns: + list: A list of directories containing language files for translation. Each directory represents + a specific language and starts with the 'values-' extension. + + Example: + Input: + get_languages_dirs('/path/to/modules') + Output: + ['values-ar', 'values-uk', ...] + """ + try: + lang_parent_dir = os.path.join(modules_dir, 'i18n', 'src', 'main', 'res') + languages_dirs = [ + directory for directory in os.listdir(lang_parent_dir) + if ( + directory.startswith('values-') + and 'strings.xml' in os.listdir(os.path.join(lang_parent_dir, directory)) + ) + ] + return languages_dirs + except FileNotFoundError as e: + print(f"Directory not found: {e}", file=sys.stderr) + raise + except PermissionError as e: + print(f"Permission denied: {e}", file=sys.stderr) + raise + + +def separate_translation_to_modules(modules_dir, lang_dir): + """ + Separates translations from a translation file into modules. + + Args: + modules_dir (str): The directory containing all the modules. + lang_dir (str): The directory containing the translation file being split. + + Returns: + dict: A dictionary containing the translations separated by module. + { + 'module_1_name': etree.Element('resources')_1. + 'module_2_name': etree.Element('resources')_2. + ... + } + """ + translations_roots = {} + try: + # Parse the translation file + file_path = get_translation_file_path(modules_dir, 'i18n', lang_dir) + module_translations_tree = etree.parse(file_path) + root = module_translations_tree.getroot() + previous_entry = None + + # Iterate through translation entries, with index starting from 1 for readablity + for i, translation_entry in enumerate(root.getchildren(), start=1): + try: + if not isinstance(translation_entry, etree._Comment): + # Split the key to extract the module name + module_name, key_remainder = translation_entry.attrib['name'].split('.', maxsplit=1) + translation_entry.attrib['name'] = key_remainder + + # Create a dictionary entry for the module if it doesn't exist + if module_name not in translations_roots: + translations_roots[module_name] = etree.Element('resources') + translations_roots[module_name].text = '\n\t' + + # Append the translation entry to the corresponding module + append_element_and_comment(translation_entry, previous_entry, translations_roots[module_name]) + + previous_entry = translation_entry + + except KeyError as e: + print(f"Error processing entry #{i}: Missing key in translation entry: {e}", file=sys.stderr) + raise + except ValueError as e: + print(f"Error processing entry #{i}: Error splitting module name: {e}", file=sys.stderr) + raise + except Exception as e: + print(f"Error processing entry #{i}: {e}", file=sys.stderr) + raise + + return translations_roots + + except FileNotFoundError as e: + print(f"Error: Translation file not found: {e}", file=sys.stderr) + raise + except etree.XMLSyntaxError as e: + print(f"Error: XML syntax error in translation file: {e}", file=sys.stderr) + raise + except Exception as e: + print(f"Error: In \"separate_translation_to_modules\" an unexpected error occurred: {e}", file=sys.stderr) + raise + + +def split_translation_files(modules_dir=None): + """ + Splits translation files into separate files for each module and language. + + Args: + modules_dir (str, optional): The directory containing all the modules. Defaults to None. + + """ + try: + # Set the modules directory if not provided + if not modules_dir: + modules_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + # Get the directories containing language files + languages_dirs = get_languages_dirs(modules_dir) + + # Iterate through each language directory + for lang_dir in languages_dirs: + translations = separate_translation_to_modules(modules_dir, lang_dir) + # Iterate through each module and write its translations to a file + for module, root in translations.items(): + # Unindent the resources closing tag + root[-1].tail = '\n' + # Write the translation file for the module and language + write_translation_file(modules_dir, root, module, lang_dir) + + except Exception as e: + print(f"Error: In \"split_translation_files\" an unexpected error occurred: {e}", file=sys.stderr) + raise + + +def replace_underscores(modules_dir=None): + try: + if not modules_dir: + modules_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + languages_dirs = get_languages_dirs(modules_dir) + + for lang_dir in languages_dirs: + try: + pattern = r'(values-\w\w)_' + if re.search(pattern, lang_dir): + replacement = r'\1-r' + new_name = re.sub(pattern, replacement, lang_dir, 1) + lang_old_path = os.path.dirname(get_translation_file_path(modules_dir, 'i18n', lang_dir)) + lang_new_path = os.path.dirname(get_translation_file_path(modules_dir, 'i18n', new_name)) + + os.rename(lang_old_path, lang_new_path) + print(f"Renamed {lang_old_path} to {lang_new_path}") + + except FileNotFoundError as e: + print(f"Error: The file or directory {lang_old_path} does not exist: {e}", file=sys.stderr) + raise + except PermissionError as e: + print(f"Error: Permission denied while renaming {lang_old_path}: {e}", file=sys.stderr) + raise + except Exception as e: + print(f"Error: An unexpected error occurred while renaming {lang_old_path} to {lang_new_path}: {e}", + file=sys.stderr) + raise + + except Exception as e: + print(f"Error: An unexpected error occurred in rename_translations_files: {e}", file=sys.stderr) + raise + + +def main(): + args = parse_arguments() + if args.split: + if args.replace_underscore: + replace_underscores() + split_translation_files() + elif args.combine: + combine_translation_files() + + +if __name__ == "__main__": + main() From dbd02e3a573274447ecf42a97252c4a34b7b573b Mon Sep 17 00:00:00 2001 From: Omar Al-Ithawi Date: Sun, 16 Jun 2024 01:59:03 +0300 Subject: [PATCH 20/38] fix: English plurals error in transifex should be `one` and `other` (#341) --- discovery/src/main/res/values/strings.xml | 4 ---- discussion/src/main/res/values/strings.xml | 24 ---------------------- 2 files changed, 28 deletions(-) diff --git a/discovery/src/main/res/values/strings.xml b/discovery/src/main/res/values/strings.xml index 5a02b65cf..1d2d9c44b 100644 --- a/discovery/src/main/res/values/strings.xml +++ b/discovery/src/main/res/values/strings.xml @@ -16,11 +16,7 @@ Programs - Found %s courses on your request Found %s course on your request - Found %s courses on your request - Found %s courses on your request - Found %s courses on your request Found %s courses on your request diff --git a/discussion/src/main/res/values/strings.xml b/discussion/src/main/res/values/strings.xml index 2527da01f..a9b11d04d 100644 --- a/discussion/src/main/res/values/strings.xml +++ b/discussion/src/main/res/values/strings.xml @@ -39,56 +39,32 @@ - %1$d votes %1$d vote - %1$d votes - %1$d votes - %1$d votes %1$d votes - %1$d Comments %1$d Comment - %1$d Comments - %1$d Comments - %1$d Comments %1$d Comments - %1$d Missed posts %1$d Missed post - %1$d Missed posts - %1$d Missed posts - %1$d Missed posts %1$d Missed posts - %1$d responses %1$d response - %1$d responses - %1$d responses - %1$d responses %1$d responses - %1$d Responses %1$d Response - %1$d Responses - %1$d Responses - %1$d Responses %1$d Responses - Found %s posts Found %s post - Found %s posts - Found %s posts - Found %s posts Found %s posts From 05c3544660ed3cb6dabea207d0424c762bdd5dd0 Mon Sep 17 00:00:00 2001 From: Volodymyr Chekyrta <127732735+volodymyr-chekyrta@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:45:07 +0300 Subject: [PATCH 21/38] fix: secondary courses view all button behavior (#345) --- .../java/org/openedx/app/di/ScreenModule.kt | 27 +++++++++++++++++-- .../presentation/DashboardGalleryView.kt | 16 +++++++---- .../presentation/DashboardGalleryViewModel.kt | 14 +++++++++- .../data/repository/DashboardRepository.kt | 3 ++- .../domain/interactor/DashboardInteractor.kt | 2 +- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 0c2c85474..11e70d4f8 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -14,6 +14,7 @@ import org.openedx.auth.presentation.signup.SignUpViewModel import org.openedx.core.Validator import org.openedx.core.presentation.dialog.selectorbottomsheet.SelectDialogViewModel import org.openedx.core.presentation.settings.video.VideoQualityViewModel +import org.openedx.core.ui.WindowSize import org.openedx.course.data.repository.CourseRepository import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.container.CourseContainerViewModel @@ -67,7 +68,18 @@ import org.openedx.whatsnew.presentation.whatsnew.WhatsNewViewModel val screenModule = module { - viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get(), get(), get()) } + viewModel { + AppViewModel( + get(), + get(), + get(), + get(), + get(named("IODispatcher")), + get(), + get(), + get() + ) + } viewModel { MainViewModel(get(), get(), get()) } factory { AuthRepository(get(), get(), get()) } @@ -121,7 +133,18 @@ val screenModule = module { factory { DashboardRepository(get(), get(), get(), get()) } factory { DashboardInteractor(get()) } viewModel { DashboardListViewModel(get(), get(), get(), get(), get(), get(), get()) } - viewModel { DashboardGalleryViewModel(get(), get(), get(), get(), get(), get(), get()) } + viewModel { (windowSize: WindowSize) -> + DashboardGalleryViewModel( + get(), + get(), + get(), + get(), + get(), + get(), + get(), + windowSize + ) + } viewModel { AllEnrolledCoursesViewModel(get(), get(), get(), get(), get(), get(), get()) } viewModel { LearnViewModel(get(), get()) } diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt index 74515e0c1..7401f6304 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt @@ -66,6 +66,7 @@ import androidx.fragment.app.FragmentManager import coil.compose.AsyncImage import coil.request.ImageRequest import org.koin.androidx.compose.koinViewModel +import org.koin.core.parameter.parametersOf import org.openedx.Lock import org.openedx.core.UIMessage import org.openedx.core.domain.model.AppConfig @@ -100,7 +101,8 @@ import org.openedx.core.R as CoreR fun DashboardGalleryView( fragmentManager: FragmentManager, ) { - val viewModel: DashboardGalleryViewModel = koinViewModel() + val windowSize = rememberWindowSize() + val viewModel: DashboardGalleryViewModel = koinViewModel { parametersOf(windowSize) } val updating by viewModel.updating.collectAsState(false) val uiMessage by viewModel.uiMessage.collectAsState(null) val uiState by viewModel.uiState.collectAsState(DashboardGalleryUIState.Loading) @@ -293,6 +295,7 @@ private fun UserCourses( if (userCourses.enrollments.courses.isNotEmpty()) { SecondaryCourses( courses = userCourses.enrollments.courses, + hasNextPage = userCourses.enrollments.pagination.next.isNotEmpty(), apiHostUrl = apiHostUrl, onCourseClick = openCourse, onViewAllClick = onViewAllClick @@ -304,6 +307,7 @@ private fun UserCourses( @Composable private fun SecondaryCourses( courses: List, + hasNextPage: Boolean, apiHostUrl: String, onCourseClick: (EnrolledCourse) -> Unit, onViewAllClick: () -> Unit @@ -342,10 +346,12 @@ private fun SecondaryCourses( onCourseClick = onCourseClick ) } - item { - ViewAllItem( - onViewAllClick = onViewAllClick - ) + if (hasNextPage) { + item { + ViewAllItem( + onViewAllClick = onViewAllClick + ) + } } } ) diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt index 6ff7ba3fd..136b914e8 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt @@ -21,6 +21,7 @@ import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CourseDashboardUpdate import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.core.system.notifier.NavigationToDiscovery +import org.openedx.core.ui.WindowSize import org.openedx.core.utils.FileUtil import org.openedx.dashboard.domain.interactor.DashboardInteractor import org.openedx.dashboard.presentation.DashboardRouter @@ -33,6 +34,7 @@ class DashboardGalleryViewModel( private val networkConnection: NetworkConnection, private val fileUtil: FileUtil, private val dashboardRouter: DashboardRouter, + private val windowSize: WindowSize ) : BaseViewModel() { val apiHostUrl get() = config.getApiHostURL() @@ -62,7 +64,12 @@ class DashboardGalleryViewModel( viewModelScope.launch { try { if (networkConnection.isOnline()) { - val response = interactor.getMainUserCourses() + val pageSize = if (windowSize.isTablet) { + PAGE_SIZE_TABLET + } else { + PAGE_SIZE_PHONE + } + val response = interactor.getMainUserCourses(pageSize) if (response.primary == null && response.enrollments.courses.isEmpty()) { _uiState.value = DashboardGalleryUIState.Empty } else { @@ -127,4 +134,9 @@ class DashboardGalleryViewModel( } } } + + companion object { + private const val PAGE_SIZE_TABLET = 7 + private const val PAGE_SIZE_PHONE = 5 + } } diff --git a/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt b/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt index 22637f48c..a65ca8d07 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/data/repository/DashboardRepository.kt @@ -35,9 +35,10 @@ class DashboardRepository( return list.map { it.mapToDomain() } } - suspend fun getMainUserCourses(): CourseEnrollments { + suspend fun getMainUserCourses(pageSize: Int): CourseEnrollments { val result = api.getUserCourses( username = preferencesManager.user?.username ?: "", + pageSize = pageSize ) preferencesManager.appConfig = result.configs.mapToDomain() diff --git a/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt b/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt index ae2e94d93..ac1870c7b 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/domain/interactor/DashboardInteractor.kt @@ -14,7 +14,7 @@ class DashboardInteractor( suspend fun getEnrolledCoursesFromCache() = repository.getEnrolledCoursesFromCache() - suspend fun getMainUserCourses() = repository.getMainUserCourses() + suspend fun getMainUserCourses(pageSize: Int) = repository.getMainUserCourses(pageSize) suspend fun getAllUserCourses( page: Int = 1, From 7ff0ff4a81e4a9f0c3031ec9d460ce173f1ce37e Mon Sep 17 00:00:00 2001 From: Omar Al-Ithawi Date: Fri, 21 Jun 2024 11:55:11 +0300 Subject: [PATCH 22/38] chore: validate plurals in strings.xml | FC-55 (#348) * chore: validate plurals in strings.xml * fix: more plurals fixes on English --- .../workflows/validate-english-strings.yml | 32 +++++++++++++++++++ Makefile | 13 ++++++++ core/src/main/res/values/strings.xml | 8 ----- course/src/main/res/values/strings.xml | 4 --- dashboard/src/main/res/values/strings.xml | 4 --- 5 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/validate-english-strings.yml diff --git a/.github/workflows/validate-english-strings.yml b/.github/workflows/validate-english-strings.yml new file mode 100644 index 000000000..43935b05e --- /dev/null +++ b/.github/workflows/validate-english-strings.yml @@ -0,0 +1,32 @@ +name: Validate English strings.xml + +on: + pull_request: { } + push: + branches: [ main, develop ] + +jobs: + translation_strings: + name: Validate strings.xml + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Use Python + uses: actions/setup-python@v5 + with: + python-version: 3.11 + + - name: Install translations requirements + run: make translation_requirements + + - name: Validate English plurals in strings.xml + run: make validate_english_plurals + + - name: Test extract strings + run: | + make extract_translations + # Ensure the file is extracted + test -f i18n/src/main/res/values/strings.xml diff --git a/Makefile b/Makefile index e7ff3745b..a0ba67b45 100644 --- a/Makefile +++ b/Makefile @@ -10,3 +10,16 @@ pull_translations: clean_translations_temp_directory extract_translations: clean_translations_temp_directory python3 i18n_scripts/translation.py --combine + +validate_english_plurals: + @if git grep 'quantity' -- '**/res/values/strings.xml' | grep -E 'quantity=.(zero|two|few|many)'; then \ + echo ""; \ + echo ""; \ + echo "Error: Found invalid plurals in the files listed above."; \ + echo " Please only use 'one' and 'other' in English strings.xml files,"; \ + echo " otherwise Transifex fails to parse them."; \ + echo ""; \ + exit 1; \ + else \ + echo "strings.xml files are valid."; \ + fi diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 580d262ac..931d2c6da 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -100,19 +100,11 @@ Due Tomorrow Due Yesterday - Due %1$d days ago Due %1$d day ago - Due %1$d days ago - Due %1$d days ago - Due %1$d days ago Due %1$d days ago - Due in %1$d days Due in %1$d day - Due in %1$d days - Due in %1$d days - Due in %1$d days Due in %1$d days diff --git a/course/src/main/res/values/strings.xml b/course/src/main/res/values/strings.xml index 2fcb1d950..51ac39e95 100644 --- a/course/src/main/res/values/strings.xml +++ b/course/src/main/res/values/strings.xml @@ -65,11 +65,7 @@ %1$s - %2$s - %3$d / %4$d - %1$s of %2$s assignments complete %1$s of %2$s assignment complete - %1$s of %2$s assignments complete - %1$s of %2$s assignments complete - %1$s of %2$s assignments complete %1$s of %2$s assignments complete diff --git a/dashboard/src/main/res/values/strings.xml b/dashboard/src/main/res/values/strings.xml index f83c35a2f..80c05bc42 100644 --- a/dashboard/src/main/res/values/strings.xml +++ b/dashboard/src/main/res/values/strings.xml @@ -21,11 +21,7 @@ No %1$s Courses - %1$d Past Due Assignments %1$d Past Due Assignment - %1$d Past Due Assignments - %1$d Past Due Assignments - %1$d Past Due Assignments %1$d Past Due Assignments From 948277af5a7621ffe795b6171684d8eaa078cc46 Mon Sep 17 00:00:00 2001 From: Volodymyr Chekyrta <127732735+volodymyr-chekyrta@users.noreply.github.com> Date: Tue, 25 Jun 2024 12:32:38 +0200 Subject: [PATCH 23/38] feat: [FC-0047] FCM (#344) * feat: fcm * fix: address feedback --- app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 4 +- .../main/java/org/openedx/app/AppActivity.kt | 16 + .../main/java/org/openedx/app/AppViewModel.kt | 62 ++- .../openedx/app/data/api/NotificationsApi.kt | 14 + .../data/networking/AppUpgradeInterceptor.kt | 12 +- .../OauthRefreshTokenAuthenticator.kt | 8 +- .../app/data/storage/PreferencesManager.kt | 8 + .../java/org/openedx/app/deeplink/DeepLink.kt | 41 +- .../openedx/app/deeplink/DeepLinkRouter.kt | 406 +++++++++++------- .../java/org/openedx/app/deeplink/Screen.kt | 20 - .../main/java/org/openedx/app/di/AppModule.kt | 6 +- .../org/openedx/app/di/NetworkingModule.kt | 2 + .../java/org/openedx/app/di/ScreenModule.kt | 1 + .../openedx/app/system/notifier/AppEvent.kt | 3 - .../app/system/notifier/LogoutEvent.kt | 3 - .../push/OpenEdXFirebaseMessagingService.kt | 95 ++++ .../system/push/RefreshFirebaseTokenWorker.kt | 46 ++ .../system/push/SyncFirebaseTokenWorker.kt | 47 ++ .../test/java/org/openedx/AppViewModelTest.kt | 87 ++-- .../restore/RestorePasswordViewModel.kt | 12 +- .../presentation/signin/SignInViewModel.kt | 15 +- .../auth/presentation/signup/SignUpUIState.kt | 2 +- .../presentation/signup/SignUpViewModel.kt | 14 +- .../restore/RestorePasswordViewModelTest.kt | 34 +- .../signin/SignInViewModelTest.kt | 33 +- .../signup/SignUpViewModelTest.kt | 34 +- build.gradle | 6 +- .../java/org/openedx/core/AppUpdateState.kt | 2 +- .../core/data/storage/CorePreferences.kt | 1 + .../system/notifier/AppUpgradeNotifier.kt | 15 - .../core/system/notifier/app/AppEvent.kt | 3 + .../core/system/notifier/app}/AppNotifier.kt | 8 +- .../notifier/{ => app}/AppUpgradeEvent.kt | 4 +- .../core/system/notifier/app/LogoutEvent.kt | 3 + .../core/system/notifier/app/SignInEvent.kt | 3 + .../container/CourseContainerFragment.kt | 14 + .../presentation/DashboardGalleryViewModel.kt | 7 + .../presentation/DashboardListFragment.kt | 2 +- .../presentation/DashboardListViewModel.kt | 15 +- .../presentation/DashboardViewModelTest.kt | 46 +- .../presentation/NativeDiscoveryFragment.kt | 2 +- .../presentation/NativeDiscoveryViewModel.kt | 9 +- .../NativeDiscoveryViewModelTest.kt | 26 +- .../discussion/data/api/DiscussionApi.kt | 11 +- .../data/model/response/CommentsResponse.kt | 6 +- .../data/repository/DiscussionRepository.kt | 9 +- .../domain/interactor/DiscussionInteractor.kt | 5 +- .../presentation/settings/SettingsScreenUI.kt | 2 +- .../settings/SettingsViewModel.kt | 14 +- 50 files changed, 839 insertions(+), 405 deletions(-) create mode 100644 app/src/main/java/org/openedx/app/data/api/NotificationsApi.kt delete mode 100644 app/src/main/java/org/openedx/app/deeplink/Screen.kt delete mode 100644 app/src/main/java/org/openedx/app/system/notifier/AppEvent.kt delete mode 100644 app/src/main/java/org/openedx/app/system/notifier/LogoutEvent.kt create mode 100644 app/src/main/java/org/openedx/app/system/push/OpenEdXFirebaseMessagingService.kt create mode 100644 app/src/main/java/org/openedx/app/system/push/RefreshFirebaseTokenWorker.kt create mode 100644 app/src/main/java/org/openedx/app/system/push/SyncFirebaseTokenWorker.kt delete mode 100644 core/src/main/java/org/openedx/core/system/notifier/AppUpgradeNotifier.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/app/AppEvent.kt rename {app/src/main/java/org/openedx/app/system/notifier => core/src/main/java/org/openedx/core/system/notifier/app}/AppNotifier.kt (67%) rename core/src/main/java/org/openedx/core/system/notifier/{ => app}/AppUpgradeEvent.kt (61%) create mode 100644 core/src/main/java/org/openedx/core/system/notifier/app/LogoutEvent.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/app/SignInEvent.kt diff --git a/app/build.gradle b/app/build.gradle index f949e477f..e0992b266 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -130,6 +130,9 @@ dependencies { implementation 'androidx.core:core-splashscreen:1.0.1' + api platform("com.google.firebase:firebase-bom:$firebase_version") + api "com.google.firebase:firebase-messaging" + // Segment Library implementation "com.segment.analytics.kotlin:android:1.14.2" // Segment's Firebase integration @@ -138,9 +141,6 @@ dependencies { implementation "com.braze:braze-segment-kotlin:1.4.2" implementation "com.braze:android-sdk-ui:30.2.0" - // Firebase Cloud Messaging Integration for Braze - implementation 'com.google.firebase:firebase-messaging-ktx:23.4.1' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index efc65add4..a3921ac64 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -105,9 +105,9 @@ android:foregroundServiceType="dataSync" tools:node="merge" /> - + diff --git a/app/src/main/java/org/openedx/app/AppActivity.kt b/app/src/main/java/org/openedx/app/AppActivity.kt index 9781b0ca7..c8d4c9259 100644 --- a/app/src/main/java/org/openedx/app/AppActivity.kt +++ b/app/src/main/java/org/openedx/app/AppActivity.kt @@ -13,6 +13,7 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat import androidx.fragment.app.Fragment import androidx.window.layout.WindowMetricsCalculator +import com.braze.support.toStringMap import io.branch.referral.Branch import io.branch.referral.Branch.BranchUniversalReferralInitListener import org.koin.android.ext.android.inject @@ -135,6 +136,11 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder { addFragment(MainFragment.newInstance()) } } + + val extras = intent.extras + if (extras?.containsKey(DeepLink.Keys.NOTIFICATION_TYPE.value) == true) { + handlePushNotification(extras) + } } viewModel.logoutUser.observe(this) { @@ -170,6 +176,11 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder { super.onNewIntent(intent) this.intent = intent + val extras = intent?.extras + if (extras?.containsKey(DeepLink.Keys.NOTIFICATION_TYPE.value) == true) { + handlePushNotification(extras) + } + if (viewModel.isBranchEnabled) { if (intent?.getBooleanExtra(BRANCH_FORCE_NEW_SESSION, false) == true) { Branch.sessionBuilder(this).withCallback { referringParams, error -> @@ -218,6 +229,11 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder { } } + private fun handlePushNotification(data: Bundle) { + val deepLink = DeepLink(data.toStringMap()) + viewModel.makeExternalRoute(supportFragmentManager, deepLink) + } + companion object { const val TOP_INSET = "topInset" const val BOTTOM_INSET = "bottomInset" diff --git a/app/src/main/java/org/openedx/app/AppViewModel.kt b/app/src/main/java/org/openedx/app/AppViewModel.kt index 3fc49859f..20b3b0c97 100644 --- a/app/src/main/java/org/openedx/app/AppViewModel.kt +++ b/app/src/main/java/org/openedx/app/AppViewModel.kt @@ -1,5 +1,8 @@ package org.openedx.app +import android.annotation.SuppressLint +import android.app.NotificationManager +import android.content.Context import androidx.fragment.app.FragmentManager import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData @@ -10,14 +13,20 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.openedx.app.deeplink.DeepLink import org.openedx.app.deeplink.DeepLinkRouter -import org.openedx.app.system.notifier.AppNotifier -import org.openedx.app.system.notifier.LogoutEvent +import org.openedx.app.system.push.RefreshFirebaseTokenWorker +import org.openedx.app.system.push.SyncFirebaseTokenWorker import org.openedx.core.BaseViewModel import org.openedx.core.SingleEventLiveData import org.openedx.core.config.Config +import org.openedx.core.data.model.User import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.LogoutEvent +import org.openedx.core.system.notifier.app.SignInEvent import org.openedx.core.utils.FileUtil + +@SuppressLint("StaticFieldLeak") class AppViewModel( private val config: Config, private val notifier: AppNotifier, @@ -27,6 +36,7 @@ class AppViewModel( private val analytics: AppAnalytics, private val deepLinkRouter: DeepLinkRouter, private val fileUtil: FileUtil, + private val context: Context ) : BaseViewModel() { private val _logoutUser = SingleEventLiveData() @@ -42,20 +52,25 @@ class AppViewModel( override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) - setUserId() + + val user = preferencesManager.user + + setUserId(user) + + if (user != null && preferencesManager.pushToken.isNotEmpty()) { + SyncFirebaseTokenWorker.schedule(context) + } + if (canResetAppDirectory) { resetAppDirectory() } + viewModelScope.launch { notifier.notifier.collect { event -> - if (event is LogoutEvent && System.currentTimeMillis() - logoutHandledAt > 5000) { - logoutHandledAt = System.currentTimeMillis() - preferencesManager.clear() - withContext(dispatcher) { - room.clearAllTables() - } - analytics.logoutEvent(true) - _logoutUser.value = Unit + if (event is SignInEvent && config.getFirebaseConfig().isCloudMessagingEnabled) { + SyncFirebaseTokenWorker.schedule(context) + } else if (event is LogoutEvent) { + handleLogoutEvent(event) } } } @@ -79,9 +94,30 @@ class AppViewModel( deepLinkRouter.makeRoute(fm, deepLink) } - private fun setUserId() { - preferencesManager.user?.let { + private fun setUserId(user: User?) { + user?.let { analytics.setUserIdForSession(it.id) } } + + private suspend fun handleLogoutEvent(event: LogoutEvent) { + if (System.currentTimeMillis() - logoutHandledAt > 5000) { + if (event.isForced) { + logoutHandledAt = System.currentTimeMillis() + preferencesManager.clear() + withContext(dispatcher) { + room.clearAllTables() + } + analytics.logoutEvent(true) + _logoutUser.value = Unit + } + + if (config.getFirebaseConfig().isCloudMessagingEnabled) { + RefreshFirebaseTokenWorker.schedule(context) + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.cancelAll() + } + } + } } diff --git a/app/src/main/java/org/openedx/app/data/api/NotificationsApi.kt b/app/src/main/java/org/openedx/app/data/api/NotificationsApi.kt new file mode 100644 index 000000000..9106944c3 --- /dev/null +++ b/app/src/main/java/org/openedx/app/data/api/NotificationsApi.kt @@ -0,0 +1,14 @@ +package org.openedx.app.data.api + +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.POST + +interface NotificationsApi { + @POST("/api/mobile/v4/notifications/create-token/") + @FormUrlEncoded + suspend fun syncFirebaseToken( + @Field("registration_id") token: String, + @Field("active") active: Boolean = true + ) +} diff --git a/app/src/main/java/org/openedx/app/data/networking/AppUpgradeInterceptor.kt b/app/src/main/java/org/openedx/app/data/networking/AppUpgradeInterceptor.kt index 4e88eec42..abf90d7a2 100644 --- a/app/src/main/java/org/openedx/app/data/networking/AppUpgradeInterceptor.kt +++ b/app/src/main/java/org/openedx/app/data/networking/AppUpgradeInterceptor.kt @@ -4,13 +4,13 @@ import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.Response import org.openedx.app.BuildConfig -import org.openedx.core.system.notifier.AppUpgradeEvent -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.core.utils.TimeUtils import java.util.Date class AppUpgradeInterceptor( - private val appUpgradeNotifier: AppUpgradeNotifier + private val appNotifier: AppNotifier ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val response = chain.proceed(chain.request()) @@ -21,15 +21,15 @@ class AppUpgradeInterceptor( runBlocking { when { responseCode == 426 -> { - appUpgradeNotifier.send(AppUpgradeEvent.UpgradeRequiredEvent) + appNotifier.send(AppUpgradeEvent.UpgradeRequiredEvent) } BuildConfig.VERSION_NAME != latestAppVersion && lastSupportedDateTime > Date().time -> { - appUpgradeNotifier.send(AppUpgradeEvent.UpgradeRecommendedEvent(latestAppVersion)) + appNotifier.send(AppUpgradeEvent.UpgradeRecommendedEvent(latestAppVersion)) } latestAppVersion.isNotEmpty() && BuildConfig.VERSION_NAME != latestAppVersion && lastSupportedDateTime < Date().time -> { - appUpgradeNotifier.send(AppUpgradeEvent.UpgradeRequiredEvent) + appNotifier.send(AppUpgradeEvent.UpgradeRequiredEvent) } } } diff --git a/app/src/main/java/org/openedx/app/data/networking/OauthRefreshTokenAuthenticator.kt b/app/src/main/java/org/openedx/app/data/networking/OauthRefreshTokenAuthenticator.kt index 3cc6b82ae..38305c007 100644 --- a/app/src/main/java/org/openedx/app/data/networking/OauthRefreshTokenAuthenticator.kt +++ b/app/src/main/java/org/openedx/app/data/networking/OauthRefreshTokenAuthenticator.kt @@ -9,8 +9,7 @@ import okhttp3.ResponseBody.Companion.toResponseBody import okhttp3.logging.HttpLoggingInterceptor import org.json.JSONException import org.json.JSONObject -import org.openedx.app.system.notifier.AppNotifier -import org.openedx.app.system.notifier.LogoutEvent +import org.openedx.core.system.notifier.app.LogoutEvent import org.openedx.auth.data.api.AuthApi import org.openedx.auth.domain.model.AuthResponse import org.openedx.core.ApiConstants @@ -18,6 +17,7 @@ import org.openedx.core.ApiConstants.TOKEN_TYPE_JWT import org.openedx.core.BuildConfig import org.openedx.core.config.Config import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.core.utils.TimeUtils import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory @@ -119,7 +119,7 @@ class OauthRefreshTokenAuthenticator( } runBlocking { - appNotifier.send(LogoutEvent()) + appNotifier.send(LogoutEvent(true)) } } @@ -128,7 +128,7 @@ class OauthRefreshTokenAuthenticator( JWT_USER_EMAIL_MISMATCH, -> { runBlocking { - appNotifier.send(LogoutEvent()) + appNotifier.send(LogoutEvent(true)) } } } diff --git a/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt b/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt index e0b65af14..473340beb 100644 --- a/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt +++ b/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt @@ -54,6 +54,7 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences remove(ACCESS_TOKEN) remove(REFRESH_TOKEN) remove(USER) + remove(ACCOUNT) remove(EXPIRES_IN) }.apply() } @@ -70,6 +71,12 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences } get() = getString(REFRESH_TOKEN) + override var pushToken: String + set(value) { + saveString(PUSH_TOKEN, value) + } + get() = getString(PUSH_TOKEN) + override var accessTokenExpiresAt: Long set(value) { saveLong(EXPIRES_IN, value) @@ -168,6 +175,7 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences companion object { private const val ACCESS_TOKEN = "access_token" private const val REFRESH_TOKEN = "refresh_token" + private const val PUSH_TOKEN = "push_token" private const val EXPIRES_IN = "expires_in" private const val USER = "user" private const val ACCOUNT = "account" diff --git a/app/src/main/java/org/openedx/app/deeplink/DeepLink.kt b/app/src/main/java/org/openedx/app/deeplink/DeepLink.kt index 2b65a92b1..ac494df06 100644 --- a/app/src/main/java/org/openedx/app/deeplink/DeepLink.kt +++ b/app/src/main/java/org/openedx/app/deeplink/DeepLink.kt @@ -2,21 +2,58 @@ package org.openedx.app.deeplink class DeepLink(params: Map) { - val screenName = params[Keys.SCREEN_NAME.value] + private val screenName = params[Keys.SCREEN_NAME.value] + private val notificationType = params[Keys.NOTIFICATION_TYPE.value] val courseId = params[Keys.COURSE_ID.value] val pathId = params[Keys.PATH_ID.value] val componentId = params[Keys.COMPONENT_ID.value] val topicId = params[Keys.TOPIC_ID.value] val threadId = params[Keys.THREAD_ID.value] val commentId = params[Keys.COMMENT_ID.value] + val parentId = params[Keys.PARENT_ID.value] + val type = DeepLinkType.typeOf(screenName ?: notificationType ?: "") enum class Keys(val value: String) { SCREEN_NAME("screen_name"), + NOTIFICATION_TYPE("notification_type"), COURSE_ID("course_id"), PATH_ID("path_id"), COMPONENT_ID("component_id"), TOPIC_ID("topic_id"), THREAD_ID("thread_id"), - COMMENT_ID("comment_id") + COMMENT_ID("comment_id"), + PARENT_ID("parent_id"), + } +} + +enum class DeepLinkType(val type: String) { + DISCOVERY("discovery"), + DISCOVERY_COURSE_DETAIL("discovery_course_detail"), + DISCOVERY_PROGRAM_DETAIL("discovery_program_detail"), + COURSE_DASHBOARD("course_dashboard"), + COURSE_VIDEOS("course_videos"), + COURSE_DISCUSSION("course_discussion"), + COURSE_DATES("course_dates"), + COURSE_HANDOUT("course_handout"), + COURSE_ANNOUNCEMENT("course_announcement"), + COURSE_COMPONENT("course_component"), + PROGRAM("program"), + DISCUSSION_TOPIC("discussion_topic"), + DISCUSSION_POST("discussion_post"), + DISCUSSION_COMMENT("discussion_comment"), + PROFILE("profile"), + USER_PROFILE("user_profile"), + ENROLL("enroll"), + UNENROLL("unenroll"), + ADD_BETA_TESTER("add_beta_tester"), + REMOVE_BETA_TESTER("remove_beta_tester"), + FORUM_RESPONSE("forum_response"), + FORUM_COMMENT("forum_comment"), + NONE(""); + + companion object { + fun typeOf(type: String): DeepLinkType { + return entries.firstOrNull { it.type == type } ?: NONE + } } } diff --git a/app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt b/app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt index 02bc5cd0e..31564edf7 100644 --- a/app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt +++ b/app/src/main/java/org/openedx/app/deeplink/DeepLinkRouter.kt @@ -14,6 +14,8 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.presentation.course.CourseViewMode import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.handouts.HandoutsType +import org.openedx.discovery.domain.interactor.DiscoveryInteractor +import org.openedx.discovery.domain.model.Course import org.openedx.discovery.presentation.catalog.WebViewLink import org.openedx.discussion.domain.interactor.DiscussionInteractor import org.openedx.discussion.presentation.topics.DiscussionTopicsViewModel @@ -23,6 +25,7 @@ class DeepLinkRouter( private val config: Config, private val appRouter: AppRouter, private val corePreferences: CorePreferences, + private val discoveryInteractor: DiscoveryInteractor, private val courseInteractor: CourseInteractor, private val discussionInteractor: DiscussionInteractor ) : CoroutineScope { @@ -34,15 +37,14 @@ class DeepLinkRouter( get() = corePreferences.user != null fun makeRoute(fm: FragmentManager, deepLink: DeepLink) { - val screenName = deepLink.screenName ?: return - when (screenName) { + when (deepLink.type) { // Discovery - Screen.DISCOVERY.screenName -> { + DeepLinkType.DISCOVERY -> { navigateToDiscoveryScreen(fm = fm) return } - Screen.DISCOVERY_COURSE_DETAIL.screenName -> { + DeepLinkType.DISCOVERY_COURSE_DETAIL -> { navigateToCourseDetail( fm = fm, deepLink = deepLink @@ -50,13 +52,17 @@ class DeepLinkRouter( return } - Screen.DISCOVERY_PROGRAM_DETAIL.screenName -> { + DeepLinkType.DISCOVERY_PROGRAM_DETAIL -> { navigateToProgramDetail( fm = fm, deepLink = deepLink ) return } + + else -> { + //ignore + } } if (!isUserLoggedIn) { @@ -64,125 +70,162 @@ class DeepLinkRouter( return } - when (screenName) { - // Course - Screen.COURSE_DASHBOARD.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseDashboard( + when (deepLink.type) { + // Program + DeepLinkType.PROGRAM -> { + navigateToProgram( fm = fm, deepLink = deepLink ) + return } - - Screen.COURSE_VIDEOS.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseVideos( - fm = fm, - deepLink = deepLink - ) + // Profile + DeepLinkType.PROFILE, + DeepLinkType.USER_PROFILE -> { + navigateToProfile(fm = fm) + return } - - Screen.COURSE_DATES.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseDates( - fm = fm, - deepLink = deepLink - ) + else -> { + //ignore } + } - Screen.COURSE_DISCUSSION.screenName -> { + launch(Dispatchers.Main) { + val courseId = deepLink.courseId ?: return@launch navigateToDashboard(fm = fm) + val course = getCourseDetails(courseId) ?: return@launch navigateToDashboard(fm = fm) + if (!course.isEnrolled) { navigateToDashboard(fm = fm) - navigateToCourseDiscussion( - fm = fm, - deepLink = deepLink - ) + return@launch } - Screen.COURSE_HANDOUT.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseMore( - fm = fm, - deepLink = deepLink - ) - navigateToCourseHandout( - fm = fm, - deepLink = deepLink - ) - } + when (deepLink.type) { + // Course + DeepLinkType.COURSE_DASHBOARD, DeepLinkType.ENROLL, DeepLinkType.ADD_BETA_TESTER -> { + navigateToDashboard(fm = fm) + navigateToCourseDashboard( + fm = fm, + deepLink = deepLink, + courseTitle = course.name + ) + } - Screen.COURSE_ANNOUNCEMENT.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseMore( - fm = fm, - deepLink = deepLink - ) - navigateToCourseAnnouncement( - fm = fm, - deepLink = deepLink - ) - } + DeepLinkType.UNENROLL, DeepLinkType.REMOVE_BETA_TESTER -> { + navigateToDashboard(fm = fm) + } - Screen.COURSE_COMPONENT.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseDashboard( - fm = fm, - deepLink = deepLink - ) - navigateToCourseComponent( - fm = fm, - deepLink = deepLink - ) - } + DeepLinkType.COURSE_VIDEOS -> { + navigateToDashboard(fm = fm) + navigateToCourseVideos( + fm = fm, + deepLink = deepLink + ) + } - // Program - Screen.PROGRAM.screenName -> { - navigateToProgram( - fm = fm, - deepLink = deepLink - ) - } + DeepLinkType.COURSE_DATES -> { + navigateToDashboard(fm = fm) + navigateToCourseDates( + fm = fm, + deepLink = deepLink + ) + } - // Discussions - Screen.DISCUSSION_TOPIC.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseDiscussion( - fm = fm, - deepLink = deepLink - ) - navigateToDiscussionTopic( - fm = fm, - deepLink = deepLink - ) - } + DeepLinkType.COURSE_DISCUSSION -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + } - Screen.DISCUSSION_POST.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseDiscussion( - fm = fm, - deepLink = deepLink - ) - navigateToDiscussionPost( - fm = fm, - deepLink = deepLink - ) - } + DeepLinkType.COURSE_HANDOUT -> { + navigateToDashboard(fm = fm) + navigateToCourseMore( + fm = fm, + deepLink = deepLink + ) + navigateToCourseHandout( + fm = fm, + deepLink = deepLink + ) + } - Screen.DISCUSSION_COMMENT.screenName -> { - navigateToDashboard(fm = fm) - navigateToCourseDiscussion( - fm = fm, - deepLink = deepLink - ) - navigateToDiscussionComment( - fm = fm, - deepLink = deepLink - ) - } + DeepLinkType.COURSE_ANNOUNCEMENT -> { + navigateToDashboard(fm = fm) + navigateToCourseMore( + fm = fm, + deepLink = deepLink + ) + navigateToCourseAnnouncement( + fm = fm, + deepLink = deepLink + ) + } - // Profile - Screen.PROFILE.screenName, - Screen.USER_PROFILE.screenName -> { - navigateToProfile(fm = fm) + DeepLinkType.COURSE_COMPONENT -> { + navigateToDashboard(fm = fm) + navigateToCourseDashboard( + fm = fm, + deepLink = deepLink, + courseTitle = course.name + ) + navigateToCourseComponent( + fm = fm, + deepLink = deepLink + ) + } + + // Discussions + DeepLinkType.DISCUSSION_TOPIC -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + navigateToDiscussionTopic( + fm = fm, + deepLink = deepLink + ) + } + + DeepLinkType.DISCUSSION_POST -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + navigateToDiscussionPost( + fm = fm, + deepLink = deepLink + ) + } + + DeepLinkType.DISCUSSION_COMMENT, DeepLinkType.FORUM_RESPONSE -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + navigateToDiscussionResponse( + fm = fm, + deepLink = deepLink + ) + } + + DeepLinkType.FORUM_COMMENT -> { + navigateToDashboard(fm = fm) + navigateToCourseDiscussion( + fm = fm, + deepLink = deepLink + ) + navigateToDiscussionComment( + fm = fm, + deepLink = deepLink + ) + } + + else -> { + //ignore + } } } } @@ -247,12 +290,16 @@ class DeepLinkRouter( } } - private fun navigateToCourseDashboard(fm: FragmentManager, deepLink: DeepLink) { + private fun navigateToCourseDashboard( + fm: FragmentManager, + deepLink: DeepLink, + courseTitle: String + ) { deepLink.courseId?.let { courseId -> appRouter.navigateToCourseOutline( fm = fm, courseId = courseId, - courseTitle = "", + courseTitle = courseTitle, enrollmentMode = "" ) } @@ -427,53 +474,99 @@ class DeepLinkRouter( } } + private fun navigateToDiscussionResponse(fm: FragmentManager, deepLink: DeepLink) { + val courseId = deepLink.courseId + val topicId = deepLink.topicId + val threadId = deepLink.threadId + val commentId = deepLink.commentId + if (courseId == null || topicId == null || threadId == null || commentId == null) { + return + } + launch { + try { + discussionInteractor.getCourseTopics(courseId) + .find { it.id == topicId }?.let { topic -> + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionThread( + fm = fm, + action = DiscussionTopicsViewModel.TOPIC, + courseId = courseId, + topicId = topicId, + title = topic.name, + viewType = FragmentViewType.FULL_CONTENT + ) + } + } + val thread = discussionInteractor.getThread( + threadId, + courseId, + topicId + ) + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionComments( + fm = fm, + thread = thread + ) + } + val response = discussionInteractor.getResponse(commentId) + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionResponses( + fm = fm, + comment = response, + isClosed = false + ) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + private fun navigateToDiscussionComment(fm: FragmentManager, deepLink: DeepLink) { - deepLink.courseId?.let { courseId -> - deepLink.topicId?.let { topicId -> - deepLink.threadId?.let { threadId -> - deepLink.commentId?.let { commentId -> - launch { - try { - discussionInteractor.getCourseTopics(courseId) - .find { it.id == topicId }?.let { topic -> - launch(Dispatchers.Main) { - appRouter.navigateToDiscussionThread( - fm = fm, - action = DiscussionTopicsViewModel.TOPIC, - courseId = courseId, - topicId = topicId, - title = topic.name, - viewType = FragmentViewType.FULL_CONTENT - ) - } - } - val thread = discussionInteractor.getThread( - threadId, - courseId, - topicId - ) - launch(Dispatchers.Main) { - appRouter.navigateToDiscussionComments( - fm = fm, - thread = thread - ) - } - val commentsData = discussionInteractor.getThreadComment(commentId) - commentsData.results.firstOrNull()?.let { comment -> - launch(Dispatchers.Main) { - appRouter.navigateToDiscussionResponses( - fm = fm, - comment = comment, - isClosed = false - ) - } - } - } catch (e: Exception) { - e.printStackTrace() - } + val courseId = deepLink.courseId + val topicId = deepLink.topicId + val threadId = deepLink.threadId + val commentId = deepLink.commentId + val parentId = deepLink.parentId + if (courseId == null || topicId == null || threadId == null || commentId == null || parentId == null) { + return + } + launch { + try { + discussionInteractor.getCourseTopics(courseId) + .find { it.id == topicId }?.let { topic -> + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionThread( + fm = fm, + action = DiscussionTopicsViewModel.TOPIC, + courseId = courseId, + topicId = topicId, + title = topic.name, + viewType = FragmentViewType.FULL_CONTENT + ) } } + val thread = discussionInteractor.getThread( + threadId, + courseId, + topicId + ) + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionComments( + fm = fm, + thread = thread + ) } + val comment = discussionInteractor.getResponse(parentId) + launch(Dispatchers.Main) { + appRouter.navigateToDiscussionResponses( + fm = fm, + comment = comment, + isClosed = false + ) + } + } catch (e: Exception) { + e.printStackTrace() } } } @@ -504,4 +597,13 @@ class DeepLinkRouter( openTab = "PROFILE" ) } + + private suspend fun getCourseDetails(courseId: String): Course? { + return try { + discoveryInteractor.getCourseDetails(courseId) + } catch (e: Exception) { + e.printStackTrace() + null + } + } } diff --git a/app/src/main/java/org/openedx/app/deeplink/Screen.kt b/app/src/main/java/org/openedx/app/deeplink/Screen.kt deleted file mode 100644 index e877649e8..000000000 --- a/app/src/main/java/org/openedx/app/deeplink/Screen.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.openedx.app.deeplink - -enum class Screen(val screenName: String) { - DISCOVERY("discovery"), - DISCOVERY_COURSE_DETAIL("discovery_course_detail"), - DISCOVERY_PROGRAM_DETAIL("discovery_program_detail"), - COURSE_DASHBOARD("course_dashboard"), - COURSE_VIDEOS("course_videos"), - COURSE_DISCUSSION("course_discussion"), - COURSE_DATES("course_dates"), - COURSE_HANDOUT("course_handout"), - COURSE_ANNOUNCEMENT("course_announcement"), - COURSE_COMPONENT("course_component"), - PROGRAM("program"), - DISCUSSION_TOPIC("discussion_topic"), - DISCUSSION_POST("discussion_post"), - DISCUSSION_COMMENT("discussion_comment"), - PROFILE("profile"), - USER_PROFILE("user_profile"), -} diff --git a/app/src/main/java/org/openedx/app/di/AppModule.kt b/app/src/main/java/org/openedx/app/di/AppModule.kt index 1d1dc7e0c..9e3a1709d 100644 --- a/app/src/main/java/org/openedx/app/di/AppModule.kt +++ b/app/src/main/java/org/openedx/app/di/AppModule.kt @@ -18,7 +18,6 @@ import org.openedx.app.BuildConfig import org.openedx.app.data.storage.PreferencesManager import org.openedx.app.room.AppDatabase import org.openedx.app.room.DATABASE_NAME -import org.openedx.app.system.notifier.AppNotifier import org.openedx.auth.presentation.AgreementProvider import org.openedx.auth.presentation.AuthAnalytics import org.openedx.auth.presentation.AuthRouter @@ -44,11 +43,11 @@ import org.openedx.core.system.AppCookieManager import org.openedx.core.system.CalendarManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.AppUpgradeNotifier import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.core.system.notifier.DownloadNotifier import org.openedx.core.system.notifier.VideoNotifier +import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.core.utils.FileUtil import org.openedx.course.data.storage.CoursePreferences import org.openedx.course.presentation.CourseAnalytics @@ -96,7 +95,6 @@ val appModule = module { single { CourseNotifier() } single { DiscussionNotifier() } single { ProfileNotifier() } - single { AppUpgradeNotifier() } single { DownloadNotifier() } single { VideoNotifier() } single { DiscoveryNotifier() } @@ -110,7 +108,7 @@ val appModule = module { single { get() } single { get() } single { get() } - single { DeepLinkRouter(get(), get(), get(), get(), get()) } + single { DeepLinkRouter(get(), get(), get(), get(), get(), get()) } single { NetworkConnection(get()) } diff --git a/app/src/main/java/org/openedx/app/di/NetworkingModule.kt b/app/src/main/java/org/openedx/app/di/NetworkingModule.kt index c281d0465..aae32b433 100644 --- a/app/src/main/java/org/openedx/app/di/NetworkingModule.kt +++ b/app/src/main/java/org/openedx/app/di/NetworkingModule.kt @@ -3,6 +3,7 @@ package org.openedx.app.di import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import org.koin.dsl.module +import org.openedx.app.data.api.NotificationsApi import org.openedx.app.data.networking.AppUpgradeInterceptor import org.openedx.app.data.networking.HandleErrorInterceptor import org.openedx.app.data.networking.HeadersInterceptor @@ -53,6 +54,7 @@ val networkingModule = module { single { provideApi(get()) } single { provideApi(get()) } single { provideApi(get()) } + single { provideApi(get()) } } diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 11e70d4f8..3fb4667df 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -77,6 +77,7 @@ val screenModule = module { get(named("IODispatcher")), get(), get(), + get(), get() ) } diff --git a/app/src/main/java/org/openedx/app/system/notifier/AppEvent.kt b/app/src/main/java/org/openedx/app/system/notifier/AppEvent.kt deleted file mode 100644 index 1a6f750f4..000000000 --- a/app/src/main/java/org/openedx/app/system/notifier/AppEvent.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.openedx.app.system.notifier - -interface AppEvent \ No newline at end of file diff --git a/app/src/main/java/org/openedx/app/system/notifier/LogoutEvent.kt b/app/src/main/java/org/openedx/app/system/notifier/LogoutEvent.kt deleted file mode 100644 index 209ac8815..000000000 --- a/app/src/main/java/org/openedx/app/system/notifier/LogoutEvent.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.openedx.app.system.notifier - -class LogoutEvent : AppEvent diff --git a/app/src/main/java/org/openedx/app/system/push/OpenEdXFirebaseMessagingService.kt b/app/src/main/java/org/openedx/app/system/push/OpenEdXFirebaseMessagingService.kt new file mode 100644 index 000000000..60917940e --- /dev/null +++ b/app/src/main/java/org/openedx/app/system/push/OpenEdXFirebaseMessagingService.kt @@ -0,0 +1,95 @@ +package org.openedx.app.system.push + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.media.RingtoneManager +import android.os.Build +import android.os.SystemClock +import androidx.core.app.NotificationCompat +import com.braze.push.BrazeFirebaseMessagingService +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage +import org.koin.android.ext.android.inject +import org.openedx.app.AppActivity +import org.openedx.app.R +import org.openedx.core.config.Config +import org.openedx.core.data.storage.CorePreferences + +class OpenEdXFirebaseMessagingService : FirebaseMessagingService() { + + private val preferences: CorePreferences by inject() + private val config: Config by inject() + + override fun onMessageReceived(message: RemoteMessage) { + super.onMessageReceived(message) + if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, message)) { + // This Remote Message originated from Braze and a push notification was displayed. + // No further action is needed. + return + } else { + // This Remote Message did not originate from Braze. + handlePushNotification(message) + } + } + + override fun onNewToken(token: String) { + super.onNewToken(token) + preferences.pushToken = token + if (preferences.user != null) { + SyncFirebaseTokenWorker.schedule(this) + } + } + + private fun handlePushNotification(message: RemoteMessage) { + val notification = message.notification ?: return + val data = message.data + + val intent = Intent(this, AppActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) + data.forEach { (k, v) -> + intent.putExtra(k, v) + } + + val code = createId() + val pendingIntent = PendingIntent.getActivity( + this, + code, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + + val channelId = "${config.getPlatformName()}_channel" + val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) + val notificationBuilder = NotificationCompat.Builder(this, channelId) + .setSmallIcon(R.mipmap.ic_launcher) + .setContentTitle(notification.title) + .setStyle( + NotificationCompat.BigTextStyle() + .bigText(notification.body)) + .setAutoCancel(true) + .setSound(defaultSoundUri) + .setContentIntent(pendingIntent) + + val notificationManager = + getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + // Since android Oreo notification channel is needed. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + channelId, + config.getPlatformName(), + NotificationManager.IMPORTANCE_HIGH, + ) + notificationManager.createNotificationChannel(channel) + } + + notificationManager.notify(code, notificationBuilder.build()) + } + + private fun createId(): Int { + return SystemClock.uptimeMillis().toInt() + } +} diff --git a/app/src/main/java/org/openedx/app/system/push/RefreshFirebaseTokenWorker.kt b/app/src/main/java/org/openedx/app/system/push/RefreshFirebaseTokenWorker.kt new file mode 100644 index 000000000..0f37f36e3 --- /dev/null +++ b/app/src/main/java/org/openedx/app/system/push/RefreshFirebaseTokenWorker.kt @@ -0,0 +1,46 @@ +package org.openedx.app.system.push + +import android.content.Context +import androidx.work.CoroutineWorker +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager +import androidx.work.WorkerParameters +import com.google.firebase.messaging.FirebaseMessaging +import kotlinx.coroutines.tasks.await +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import org.openedx.core.data.storage.CorePreferences + +class RefreshFirebaseTokenWorker(context: Context, params: WorkerParameters) : + CoroutineWorker(context, params), + KoinComponent { + + private val preferences: CorePreferences by inject() + + override suspend fun doWork(): Result { + FirebaseMessaging.getInstance().deleteToken().await() + + val newPushToken = FirebaseMessaging.getInstance().getToken().await() + + preferences.pushToken = newPushToken + + return Result.success() + } + + companion object { + private const val WORKER_TAG = "RefreshFirebaseTokenWorker" + + fun schedule(context: Context) { + val work = OneTimeWorkRequest + .Builder(RefreshFirebaseTokenWorker::class.java) + .addTag(WORKER_TAG) + .build() + WorkManager.getInstance(context).beginUniqueWork( + WORKER_TAG, + ExistingWorkPolicy.REPLACE, + work + ).enqueue() + } + } +} diff --git a/app/src/main/java/org/openedx/app/system/push/SyncFirebaseTokenWorker.kt b/app/src/main/java/org/openedx/app/system/push/SyncFirebaseTokenWorker.kt new file mode 100644 index 000000000..ed4d841eb --- /dev/null +++ b/app/src/main/java/org/openedx/app/system/push/SyncFirebaseTokenWorker.kt @@ -0,0 +1,47 @@ +package org.openedx.app.system.push + +import android.content.Context +import androidx.work.CoroutineWorker +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager +import androidx.work.WorkerParameters +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import org.openedx.app.data.api.NotificationsApi +import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.module.DownloadWorker + +class SyncFirebaseTokenWorker(context: Context, params: WorkerParameters) : + CoroutineWorker(context, params), + KoinComponent { + + private val preferences: CorePreferences by inject() + private val api: NotificationsApi by inject() + + override suspend fun doWork(): Result { + if (preferences.user != null && preferences.pushToken.isNotEmpty()) { + + api.syncFirebaseToken(preferences.pushToken) + + return Result.success() + } + return Result.failure() + } + + companion object { + private const val WORKER_TAG = "SyncFirebaseTokenWorker" + + fun schedule(context: Context) { + val work = OneTimeWorkRequest + .Builder(SyncFirebaseTokenWorker::class.java) + .addTag(WORKER_TAG) + .build() + WorkManager.getInstance(context).beginUniqueWork( + WORKER_TAG, + ExistingWorkPolicy.REPLACE, + work + ).enqueue() + } + } +} diff --git a/app/src/test/java/org/openedx/AppViewModelTest.kt b/app/src/test/java/org/openedx/AppViewModelTest.kt index 35a2d3d96..87a34e790 100644 --- a/app/src/test/java/org/openedx/AppViewModelTest.kt +++ b/app/src/test/java/org/openedx/AppViewModelTest.kt @@ -1,5 +1,6 @@ package org.openedx +import android.content.Context import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner @@ -25,10 +26,11 @@ import org.openedx.app.deeplink.DeepLinkRouter import org.openedx.app.AppViewModel import org.openedx.app.data.storage.PreferencesManager import org.openedx.app.room.AppDatabase -import org.openedx.app.system.notifier.AppNotifier -import org.openedx.app.system.notifier.LogoutEvent +import org.openedx.core.system.notifier.app.LogoutEvent import org.openedx.core.config.Config +import org.openedx.core.config.FirebaseConfig import org.openedx.core.data.model.User +import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.core.utils.FileUtil @ExperimentalCoroutinesApi @@ -46,6 +48,7 @@ class AppViewModelTest { private val analytics = mockk() private val fileUtil = mockk() private val deepLinkRouter = mockk() + private val context = mockk() private val user = User(0, "", "", "") @@ -65,17 +68,19 @@ class AppViewModelTest { every { preferencesManager.user } returns user every { notifier.notifier } returns flow { } every { preferencesManager.canResetAppDirectory } returns false - val viewModel = - AppViewModel( - config, - notifier, - room, - preferencesManager, - dispatcher, - analytics, - deepLinkRouter, - fileUtil - ) + every { preferencesManager.pushToken } returns "" + + val viewModel = AppViewModel( + config, + notifier, + room, + preferencesManager, + dispatcher, + analytics, + deepLinkRouter, + fileUtil, + context + ) val mockLifeCycleOwner: LifecycleOwner = mockk() val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner) @@ -89,7 +94,7 @@ class AppViewModelTest { @Test fun forceLogout() = runTest { every { notifier.notifier } returns flow { - emit(LogoutEvent()) + emit(LogoutEvent(true)) } every { preferencesManager.clear() } returns Unit every { analytics.setUserIdForSession(any()) } returns Unit @@ -97,17 +102,20 @@ class AppViewModelTest { every { room.clearAllTables() } returns Unit every { analytics.logoutEvent(true) } returns Unit every { preferencesManager.canResetAppDirectory } returns false - val viewModel = - AppViewModel( - config, - notifier, - room, - preferencesManager, - dispatcher, - analytics, - deepLinkRouter, - fileUtil - ) + every { preferencesManager.pushToken } returns "" + every { config.getFirebaseConfig() } returns FirebaseConfig() + + val viewModel = AppViewModel( + config, + notifier, + room, + preferencesManager, + dispatcher, + analytics, + deepLinkRouter, + fileUtil, + context + ) val mockLifeCycleOwner: LifecycleOwner = mockk() val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner) @@ -122,8 +130,8 @@ class AppViewModelTest { @Test fun forceLogoutTwice() = runTest { every { notifier.notifier } returns flow { - emit(LogoutEvent()) - emit(LogoutEvent()) + emit(LogoutEvent(true)) + emit(LogoutEvent(true)) } every { preferencesManager.clear() } returns Unit every { analytics.setUserIdForSession(any()) } returns Unit @@ -131,17 +139,20 @@ class AppViewModelTest { every { room.clearAllTables() } returns Unit every { analytics.logoutEvent(true) } returns Unit every { preferencesManager.canResetAppDirectory } returns false - val viewModel = - AppViewModel( - config, - notifier, - room, - preferencesManager, - dispatcher, - analytics, - deepLinkRouter, - fileUtil - ) + every { preferencesManager.pushToken } returns "" + every { config.getFirebaseConfig() } returns FirebaseConfig() + + val viewModel = AppViewModel( + config, + notifier, + room, + preferencesManager, + dispatcher, + analytics, + deepLinkRouter, + fileUtil, + context + ) val mockLifeCycleOwner: LifecycleOwner = mockk() val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner) diff --git a/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordViewModel.kt index b21c694da..6827d8e78 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordViewModel.kt @@ -16,14 +16,14 @@ import org.openedx.core.extension.isEmailValid import org.openedx.core.extension.isInternetError import org.openedx.core.system.EdxError import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.AppUpgradeEvent -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent class RestorePasswordViewModel( private val interactor: AuthInteractor, private val resourceManager: ResourceManager, private val analytics: AuthAnalytics, - private val appUpgradeNotifier: AppUpgradeNotifier, + private val appNotifier: AppNotifier ) : BaseViewModel() { private val _uiState = MutableLiveData() @@ -81,8 +81,10 @@ class RestorePasswordViewModel( private fun collectAppUpgradeEvent() { viewModelScope.launch { - appUpgradeNotifier.notifier.collect { event -> - _appUpgradeEvent.value = event + appNotifier.notifier.collect { event -> + if (event is AppUpgradeEvent) { + _appUpgradeEvent.value = event + } } } } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt index 7ebc5a569..9fbd8c2fe 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt @@ -32,8 +32,9 @@ import org.openedx.core.extension.isInternetError import org.openedx.core.presentation.global.WhatsNewGlobalManager import org.openedx.core.system.EdxError import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.AppUpgradeEvent -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent +import org.openedx.core.system.notifier.app.SignInEvent import org.openedx.core.utils.Logger import org.openedx.core.R as CoreRes @@ -42,7 +43,7 @@ class SignInViewModel( private val resourceManager: ResourceManager, private val preferencesManager: CorePreferences, private val validator: Validator, - private val appUpgradeNotifier: AppUpgradeNotifier, + private val appNotifier: AppNotifier, private val analytics: AuthAnalytics, private val oAuthHelper: OAuthHelper, private val router: AuthRouter, @@ -107,6 +108,7 @@ class SignInViewModel( ) } ) + appNotifier.send(SignInEvent()) } catch (e: Exception) { if (e is EdxError.InvalidGrantException) { _uiMessage.value = @@ -125,8 +127,10 @@ class SignInViewModel( private fun collectAppUpgradeEvent() { viewModelScope.launch { - appUpgradeNotifier.notifier.collect { event -> - _appUpgradeEvent.value = event + appNotifier.notifier.collect { event -> + if (event is AppUpgradeEvent) { + _appUpgradeEvent.value = event + } } } } @@ -170,6 +174,7 @@ class SignInViewModel( _uiState.update { it.copy(loginSuccess = true) } setUserId() _uiState.update { it.copy(showProgress = false) } + appNotifier.send(SignInEvent()) } } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt index 0f7873b78..7e60beb1d 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt @@ -2,7 +2,7 @@ package org.openedx.auth.presentation.signup import org.openedx.auth.domain.model.SocialAuthResponse import org.openedx.core.domain.model.RegistrationField -import org.openedx.core.system.notifier.AppUpgradeEvent +import org.openedx.core.system.notifier.app.AppUpgradeEvent data class SignUpUIState( val allFields: List = emptyList(), diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt index 08bbce466..42b6bf2d1 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt @@ -31,7 +31,9 @@ import org.openedx.core.domain.model.RegistrationFieldType import org.openedx.core.domain.model.createHonorCodeField import org.openedx.core.extension.isInternetError import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent +import org.openedx.core.system.notifier.app.SignInEvent import org.openedx.core.utils.Logger import org.openedx.core.R as coreR @@ -40,7 +42,7 @@ class SignUpViewModel( private val resourceManager: ResourceManager, private val analytics: AuthAnalytics, private val preferencesManager: CorePreferences, - private val appUpgradeNotifier: AppUpgradeNotifier, + private val appNotifier: AppNotifier, private val agreementProvider: AgreementProvider, private val oAuthHelper: OAuthHelper, private val config: Config, @@ -175,6 +177,7 @@ class SignUpViewModel( ) setUserId() _uiState.update { it.copy(successLogin = true, isButtonLoading = false) } + appNotifier.send(SignInEvent()) } else { exchangeToken(socialAuth) } @@ -255,6 +258,7 @@ class SignUpViewModel( ) _uiState.update { it.copy(successLogin = true) } logger.d { "Social login (${socialAuth.authType.methodName}) success" } + appNotifier.send(SignInEvent()) } } @@ -274,8 +278,10 @@ class SignUpViewModel( private fun collectAppUpgradeEvent() { viewModelScope.launch { - appUpgradeNotifier.notifier.collect { event -> - _uiState.update { it.copy(appUpgradeEvent = event) } + appNotifier.notifier.collect { event -> + if (event is AppUpgradeEvent) { + _uiState.update { it.copy(appUpgradeEvent = event) } + } } } } diff --git a/auth/src/test/java/org/openedx/auth/presentation/restore/RestorePasswordViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/restore/RestorePasswordViewModelTest.kt index 4c92b317f..0f040e908 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/restore/RestorePasswordViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/restore/RestorePasswordViewModelTest.kt @@ -26,7 +26,7 @@ import org.openedx.core.R import org.openedx.core.UIMessage import org.openedx.core.system.EdxError import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier import java.net.UnknownHostException @OptIn(ExperimentalCoroutinesApi::class) @@ -39,7 +39,7 @@ class RestorePasswordViewModelTest { private val resourceManager = mockk() private val interactor = mockk() private val analytics = mockk() - private val appUpgradeNotifier = mockk() + private val appNotifier = mockk() //region parameters @@ -60,7 +60,7 @@ class RestorePasswordViewModelTest { every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong every { resourceManager.getString(org.openedx.auth.R.string.auth_invalid_email) } returns invalidEmail every { resourceManager.getString(org.openedx.auth.R.string.auth_invalid_password) } returns invalidPassword - every { appUpgradeNotifier.notifier } returns emptyFlow() + every { appNotifier.notifier } returns emptyFlow() } @After @@ -71,14 +71,14 @@ class RestorePasswordViewModelTest { @Test fun `passwordReset empty email validation error`() = runTest { val viewModel = - RestorePasswordViewModel(interactor, resourceManager, analytics, appUpgradeNotifier) + RestorePasswordViewModel(interactor, resourceManager, analytics, appNotifier) coEvery { interactor.passwordReset(emptyEmail) } returns true every { analytics.logEvent(any(), any()) } returns Unit viewModel.passwordReset(emptyEmail) advanceUntilIdle() coVerify(exactly = 0) { interactor.passwordReset(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage @@ -89,14 +89,14 @@ class RestorePasswordViewModelTest { @Test fun `passwordReset invalid email validation error`() = runTest { val viewModel = - RestorePasswordViewModel(interactor, resourceManager, analytics, appUpgradeNotifier) + RestorePasswordViewModel(interactor, resourceManager, analytics, appNotifier) coEvery { interactor.passwordReset(invalidEmail) } returns true every { analytics.logEvent(any(), any()) } returns Unit viewModel.passwordReset(invalidEmail) advanceUntilIdle() coVerify(exactly = 0) { interactor.passwordReset(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage @@ -107,14 +107,14 @@ class RestorePasswordViewModelTest { @Test fun `passwordReset validation error`() = runTest { val viewModel = - RestorePasswordViewModel(interactor, resourceManager, analytics, appUpgradeNotifier) + RestorePasswordViewModel(interactor, resourceManager, analytics, appNotifier) coEvery { interactor.passwordReset(correctEmail) } throws EdxError.ValidationException("error") every { analytics.logEvent(any(), any()) } returns Unit viewModel.passwordReset(correctEmail) advanceUntilIdle() coVerify(exactly = 1) { interactor.passwordReset(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage @@ -125,14 +125,14 @@ class RestorePasswordViewModelTest { @Test fun `passwordReset no internet error`() = runTest { val viewModel = - RestorePasswordViewModel(interactor, resourceManager, analytics, appUpgradeNotifier) + RestorePasswordViewModel(interactor, resourceManager, analytics, appNotifier) coEvery { interactor.passwordReset(correctEmail) } throws UnknownHostException() every { analytics.logEvent(any(), any()) } returns Unit viewModel.passwordReset(correctEmail) advanceUntilIdle() coVerify(exactly = 1) { interactor.passwordReset(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage @@ -143,14 +143,14 @@ class RestorePasswordViewModelTest { @Test fun `passwordReset unknown error`() = runTest { val viewModel = - RestorePasswordViewModel(interactor, resourceManager, analytics, appUpgradeNotifier) + RestorePasswordViewModel(interactor, resourceManager, analytics, appNotifier) coEvery { interactor.passwordReset(correctEmail) } throws Exception() every { analytics.logEvent(any(), any()) } returns Unit viewModel.passwordReset(correctEmail) advanceUntilIdle() coVerify(exactly = 1) { interactor.passwordReset(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage @@ -161,14 +161,14 @@ class RestorePasswordViewModelTest { @Test fun `unSuccess restore password`() = runTest { val viewModel = - RestorePasswordViewModel(interactor, resourceManager, analytics, appUpgradeNotifier) + RestorePasswordViewModel(interactor, resourceManager, analytics, appNotifier) coEvery { interactor.passwordReset(correctEmail) } returns false every { analytics.logEvent(any(), any()) } returns Unit viewModel.passwordReset(correctEmail) advanceUntilIdle() coVerify(exactly = 1) { interactor.passwordReset(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage @@ -180,14 +180,14 @@ class RestorePasswordViewModelTest { @Test fun `success restore password`() = runTest { val viewModel = - RestorePasswordViewModel(interactor, resourceManager, analytics, appUpgradeNotifier) + RestorePasswordViewModel(interactor, resourceManager, analytics, appNotifier) coEvery { interactor.passwordReset(correctEmail) } returns true every { analytics.logEvent(any(), any()) } returns Unit viewModel.passwordReset(correctEmail) advanceUntilIdle() coVerify(exactly = 1) { interactor.passwordReset(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val state = viewModel.uiState.value as? RestorePasswordUIState.Success val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage diff --git a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt index b36aabb10..d35e34040 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt @@ -38,7 +38,9 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.presentation.global.WhatsNewGlobalManager import org.openedx.core.system.EdxError import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppEvent +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.SignInEvent import java.net.UnknownHostException import org.openedx.core.R as CoreRes @@ -56,7 +58,7 @@ class SignInViewModelTest { private val preferencesManager = mockk() private val interactor = mockk() private val analytics = mockk() - private val appUpgradeNotifier = mockk() + private val appNotifier = mockk() private val agreementProvider = mockk() private val oAuthHelper = mockk() private val router = mockk() @@ -78,7 +80,7 @@ class SignInViewModelTest { every { resourceManager.getString(CoreRes.string.core_error_unknown_error) } returns somethingWrong every { resourceManager.getString(R.string.auth_invalid_email_username) } returns invalidEmailOrUsername every { resourceManager.getString(R.string.auth_invalid_password) } returns invalidPassword - every { appUpgradeNotifier.notifier } returns emptyFlow() + every { appNotifier.notifier } returns emptyFlow() every { agreementProvider.getAgreement(true) } returns null every { config.isPreLoginExperienceEnabled() } returns false every { config.isSocialAuthEnabled() } returns false @@ -104,7 +106,7 @@ class SignInViewModelTest { preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -137,7 +139,7 @@ class SignInViewModelTest { preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -171,7 +173,7 @@ class SignInViewModelTest { preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -204,7 +206,7 @@ class SignInViewModelTest { preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -233,13 +235,14 @@ class SignInViewModelTest { every { preferencesManager.user } returns user every { analytics.setUserIdForSession(any()) } returns Unit every { analytics.logEvent(any(), any()) } returns Unit + coEvery { appNotifier.send(any()) } returns Unit val viewModel = SignInViewModel( interactor = interactor, resourceManager = resourceManager, preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -255,7 +258,7 @@ class SignInViewModelTest { coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 1) { analytics.setUserIdForSession(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val uiState = viewModel.uiState.value assertFalse(uiState.showProgress) assert(uiState.loginSuccess) @@ -275,7 +278,7 @@ class SignInViewModelTest { preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -291,7 +294,7 @@ class SignInViewModelTest { coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } verify(exactly = 1) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage val uiState = viewModel.uiState.value @@ -313,7 +316,7 @@ class SignInViewModelTest { preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -328,7 +331,7 @@ class SignInViewModelTest { coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } verify(exactly = 1) { analytics.logEvent(any(), any()) } val message = viewModel.uiMessage.value as UIMessage.SnackBarMessage @@ -351,7 +354,7 @@ class SignInViewModelTest { preferencesManager = preferencesManager, validator = validator, analytics = analytics, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -366,7 +369,7 @@ class SignInViewModelTest { coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } verify(exactly = 1) { analytics.logEvent(any(), any()) } val message = viewModel.uiMessage.value as UIMessage.SnackBarMessage diff --git a/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt index f304f7363..5be80557c 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt @@ -44,7 +44,7 @@ import org.openedx.core.domain.model.AgreementUrls import org.openedx.core.domain.model.RegistrationField import org.openedx.core.domain.model.RegistrationFieldType import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier import java.net.UnknownHostException @ExperimentalCoroutinesApi @@ -59,7 +59,7 @@ class SignUpViewModelTest { private val preferencesManager = mockk() private val interactor = mockk() private val analytics = mockk() - private val appUpgradeNotifier = mockk() + private val appNotifier = mockk() private val agreementProvider = mockk() private val oAuthHelper = mockk() private val router = mockk() @@ -111,7 +111,7 @@ class SignUpViewModelTest { every { resourceManager.getString(R.string.core_error_invalid_grant) } returns "Invalid credentials" every { resourceManager.getString(R.string.core_error_no_connection) } returns noInternet every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong - every { appUpgradeNotifier.notifier } returns emptyFlow() + every { appNotifier.notifier } returns emptyFlow() every { agreementProvider.getAgreement(false) } returns null every { config.isSocialAuthEnabled() } returns false every { config.getAgreement(Locale.current.language) } returns AgreementUrls() @@ -133,7 +133,7 @@ class SignUpViewModelTest { resourceManager = resourceManager, analytics = analytics, preferencesManager = preferencesManager, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -162,7 +162,7 @@ class SignUpViewModelTest { coVerify(exactly = 0) { interactor.register(any()) } coVerify(exactly = 0) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assertEquals(true, viewModel.uiState.value.validationError) assertFalse(viewModel.uiState.value.successLogin) @@ -176,7 +176,7 @@ class SignUpViewModelTest { resourceManager = resourceManager, analytics = analytics, preferencesManager = preferencesManager, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -210,7 +210,7 @@ class SignUpViewModelTest { coVerify(exactly = 1) { interactor.validateRegistrationFields(any()) } coVerify(exactly = 0) { interactor.register(any()) } coVerify(exactly = 0) { interactor.login(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assertFalse(viewModel.uiState.value.validationError) assertFalse(viewModel.uiState.value.successLogin) @@ -225,7 +225,7 @@ class SignUpViewModelTest { resourceManager = resourceManager, analytics = analytics, preferencesManager = preferencesManager, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -248,7 +248,7 @@ class SignUpViewModelTest { coVerify(exactly = 1) { interactor.validateRegistrationFields(any()) } coVerify(exactly = 0) { interactor.register(any()) } coVerify(exactly = 0) { interactor.login(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assertFalse(viewModel.uiState.value.validationError) assertFalse(viewModel.uiState.value.successLogin) @@ -263,7 +263,7 @@ class SignUpViewModelTest { resourceManager = resourceManager, analytics = analytics, preferencesManager = preferencesManager, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -298,7 +298,7 @@ class SignUpViewModelTest { coVerify(exactly = 1) { interactor.register(any()) } coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assertFalse(viewModel.uiState.value.validationError) assertFalse(viewModel.uiState.value.isButtonLoading) @@ -312,7 +312,7 @@ class SignUpViewModelTest { resourceManager = resourceManager, analytics = analytics, preferencesManager = preferencesManager, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -326,7 +326,7 @@ class SignUpViewModelTest { viewModel.getRegistrationFields() advanceUntilIdle() coVerify(exactly = 1) { interactor.getRegistrationFields() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assertFalse(viewModel.uiState.value.isLoading) assertEquals(noInternet, (deferred.await() as? UIMessage.SnackBarMessage)?.message) @@ -339,7 +339,7 @@ class SignUpViewModelTest { resourceManager = resourceManager, analytics = analytics, preferencesManager = preferencesManager, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -353,7 +353,7 @@ class SignUpViewModelTest { viewModel.getRegistrationFields() advanceUntilIdle() coVerify(exactly = 1) { interactor.getRegistrationFields() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assertFalse(viewModel.uiState.value.isLoading) assertEquals(somethingWrong, (deferred.await() as? UIMessage.SnackBarMessage)?.message) @@ -366,7 +366,7 @@ class SignUpViewModelTest { resourceManager = resourceManager, analytics = analytics, preferencesManager = preferencesManager, - appUpgradeNotifier = appUpgradeNotifier, + appNotifier = appNotifier, oAuthHelper = oAuthHelper, agreementProvider = agreementProvider, config = config, @@ -378,7 +378,7 @@ class SignUpViewModelTest { viewModel.getRegistrationFields() advanceUntilIdle() coVerify(exactly = 1) { interactor.getRegistrationFields() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } //val fields = viewModel.uiState.value as? SignUpUIState.Fields diff --git a/build.gradle b/build.gradle index 250f56863..c163d3982 100644 --- a/build.gradle +++ b/build.gradle @@ -16,8 +16,8 @@ plugins { id 'com.android.application' version '8.4.0' apply false id 'com.android.library' version '8.4.0' apply false id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false - id 'com.google.gms.google-services' version '4.3.15' apply false - id "com.google.firebase.crashlytics" version "2.9.6" apply false + id 'com.google.gms.google-services' version '4.4.1' apply false + id "com.google.firebase.crashlytics" version "3.0.1" apply false } tasks.register('clean', Delete) { @@ -35,7 +35,7 @@ ext { media3_version = "1.1.1" youtubeplayer_version = "11.1.0" - firebase_version = "32.1.0" + firebase_version = "33.0.0" retrofit_version = '2.9.0' logginginterceptor_version = '4.9.1' diff --git a/core/src/main/java/org/openedx/core/AppUpdateState.kt b/core/src/main/java/org/openedx/core/AppUpdateState.kt index bf347cd29..6d6a8e357 100644 --- a/core/src/main/java/org/openedx/core/AppUpdateState.kt +++ b/core/src/main/java/org/openedx/core/AppUpdateState.kt @@ -5,7 +5,7 @@ import android.content.Context import android.content.Intent import android.net.Uri import androidx.compose.runtime.mutableStateOf -import org.openedx.core.system.notifier.AppUpgradeEvent +import org.openedx.core.system.notifier.app.AppUpgradeEvent object AppUpdateState { var wasUpdateDialogDisplayed = false diff --git a/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt b/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt index f9cacbd04..29495bae8 100644 --- a/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt +++ b/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt @@ -7,6 +7,7 @@ import org.openedx.core.domain.model.VideoSettings interface CorePreferences { var accessToken: String var refreshToken: String + var pushToken: String var accessTokenExpiresAt: Long var user: User? var videoSettings: VideoSettings diff --git a/core/src/main/java/org/openedx/core/system/notifier/AppUpgradeNotifier.kt b/core/src/main/java/org/openedx/core/system/notifier/AppUpgradeNotifier.kt deleted file mode 100644 index 0f5a274d5..000000000 --- a/core/src/main/java/org/openedx/core/system/notifier/AppUpgradeNotifier.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.openedx.core.system.notifier - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.asSharedFlow - -class AppUpgradeNotifier { - - private val channel = MutableSharedFlow(replay = 0, extraBufferCapacity = 0) - - val notifier: Flow = channel.asSharedFlow() - - suspend fun send(event: AppUpgradeEvent) = channel.emit(event) - -} \ No newline at end of file diff --git a/core/src/main/java/org/openedx/core/system/notifier/app/AppEvent.kt b/core/src/main/java/org/openedx/core/system/notifier/app/AppEvent.kt new file mode 100644 index 000000000..7dd8f0407 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/app/AppEvent.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier.app + +interface AppEvent diff --git a/app/src/main/java/org/openedx/app/system/notifier/AppNotifier.kt b/core/src/main/java/org/openedx/core/system/notifier/app/AppNotifier.kt similarity index 67% rename from app/src/main/java/org/openedx/app/system/notifier/AppNotifier.kt rename to core/src/main/java/org/openedx/core/system/notifier/app/AppNotifier.kt index d0c579d8f..804d84a65 100644 --- a/app/src/main/java/org/openedx/app/system/notifier/AppNotifier.kt +++ b/core/src/main/java/org/openedx/core/system/notifier/app/AppNotifier.kt @@ -1,4 +1,4 @@ -package org.openedx.app.system.notifier +package org.openedx.core.system.notifier.app import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -10,6 +10,10 @@ class AppNotifier { val notifier: Flow = channel.asSharedFlow() + suspend fun send(event: SignInEvent) = channel.emit(event) + suspend fun send(event: LogoutEvent) = channel.emit(event) -} \ No newline at end of file + suspend fun send(event: AppUpgradeEvent) = channel.emit(event) + +} diff --git a/core/src/main/java/org/openedx/core/system/notifier/AppUpgradeEvent.kt b/core/src/main/java/org/openedx/core/system/notifier/app/AppUpgradeEvent.kt similarity index 61% rename from core/src/main/java/org/openedx/core/system/notifier/AppUpgradeEvent.kt rename to core/src/main/java/org/openedx/core/system/notifier/app/AppUpgradeEvent.kt index f99086a11..81dba6177 100644 --- a/core/src/main/java/org/openedx/core/system/notifier/AppUpgradeEvent.kt +++ b/core/src/main/java/org/openedx/core/system/notifier/app/AppUpgradeEvent.kt @@ -1,6 +1,6 @@ -package org.openedx.core.system.notifier +package org.openedx.core.system.notifier.app -sealed class AppUpgradeEvent { +sealed class AppUpgradeEvent: AppEvent { object UpgradeRequiredEvent : AppUpgradeEvent() class UpgradeRecommendedEvent(val newVersionName: String) : AppUpgradeEvent() } diff --git a/core/src/main/java/org/openedx/core/system/notifier/app/LogoutEvent.kt b/core/src/main/java/org/openedx/core/system/notifier/app/LogoutEvent.kt new file mode 100644 index 000000000..12154f3f1 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/app/LogoutEvent.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier.app + +class LogoutEvent(val isForced: Boolean) : AppEvent diff --git a/core/src/main/java/org/openedx/core/system/notifier/app/SignInEvent.kt b/core/src/main/java/org/openedx/core/system/notifier/app/SignInEvent.kt new file mode 100644 index 000000000..340d04476 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/app/SignInEvent.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier.app + +class SignInEvent : AppEvent 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 49d6b8cae..d83cd0c18 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 @@ -1,6 +1,8 @@ package org.openedx.course.presentation.container +import android.os.Build import android.os.Bundle +import android.util.Log import android.view.View import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.ExperimentalFoundationApi @@ -97,6 +99,12 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { } } + private val pushNotificationPermissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestPermission() + ) { granted -> + Log.d(CourseContainerFragment::class.java.simpleName, "Permission granted: $granted") + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel.preloadCourseStructure() @@ -130,6 +138,12 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { requireActivity().supportFragmentManager, viewModel.courseName ) + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + pushNotificationPermissionLauncher.launch( + android.Manifest.permission.POST_NOTIFICATIONS + ) + } } } viewModel.errorMessage.observe(viewLifecycleOwner) { diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt index 136b914e8..7f1036e1d 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryViewModel.kt @@ -55,6 +55,8 @@ class DashboardGalleryViewModel( val hasInternetConnection: Boolean get() = networkConnection.isOnline() + private var isLoading = false + init { collectDiscoveryNotifier() getCourses() @@ -64,6 +66,7 @@ class DashboardGalleryViewModel( viewModelScope.launch { try { if (networkConnection.isOnline()) { + isLoading = true val pageSize = if (windowSize.isTablet) { PAGE_SIZE_TABLET } else { @@ -92,11 +95,15 @@ class DashboardGalleryViewModel( } } finally { _updating.value = false + isLoading = false } } } fun updateCourses() { + if (isLoading) { + return + } _updating.value = true getCourses() } diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index e3d6abdf6..2d8e81d6b 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -82,7 +82,7 @@ import org.openedx.core.domain.model.EnrolledCourse import org.openedx.core.domain.model.EnrolledCourseData import org.openedx.core.domain.model.Progress import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRecommendedBox -import org.openedx.core.system.notifier.AppUpgradeEvent +import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.OfflineModeDialog import org.openedx.core.ui.WindowSize diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt index 82814561a..bfafc81c4 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt @@ -14,10 +14,10 @@ import org.openedx.core.domain.model.EnrolledCourse import org.openedx.core.extension.isInternetError import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.AppUpgradeEvent -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.core.system.notifier.CourseDashboardUpdate import org.openedx.core.system.notifier.DiscoveryNotifier +import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.dashboard.domain.interactor.DashboardInteractor class DashboardListViewModel( @@ -27,7 +27,7 @@ class DashboardListViewModel( private val resourceManager: ResourceManager, private val discoveryNotifier: DiscoveryNotifier, private val analytics: DashboardAnalytics, - private val appUpgradeNotifier: AppUpgradeNotifier, + private val appNotifier: AppNotifier ) : BaseViewModel() { private val coursesList = mutableListOf() @@ -82,6 +82,9 @@ class DashboardListViewModel( } fun updateCourses() { + if (isLoading) { + return + } viewModelScope.launch { try { _updating.value = true @@ -167,8 +170,10 @@ class DashboardListViewModel( private fun collectAppUpgradeEvent() { viewModelScope.launch { - appUpgradeNotifier.notifier.collect { event -> - _appUpgradeEvent.value = event + appNotifier.notifier.collect { event -> + if (event is AppUpgradeEvent) { + _appUpgradeEvent.value = event + } } } } diff --git a/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt b/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt index 6ca20a255..2a1131392 100644 --- a/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt +++ b/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt @@ -31,9 +31,9 @@ import org.openedx.core.domain.model.DashboardCourseList import org.openedx.core.domain.model.Pagination import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.AppUpgradeNotifier import org.openedx.core.system.notifier.CourseDashboardUpdate import org.openedx.core.system.notifier.DiscoveryNotifier +import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.dashboard.domain.interactor.DashboardInteractor import java.net.UnknownHostException @@ -51,7 +51,7 @@ class DashboardViewModelTest { private val networkConnection = mockk() private val discoveryNotifier = mockk() private val analytics = mockk() - private val appUpgradeNotifier = mockk() + private val appNotifier = mockk() private val noInternet = "Slow or no internet connection" private val somethingWrong = "Something went wrong" @@ -66,7 +66,7 @@ class DashboardViewModelTest { Dispatchers.setMain(dispatcher) every { resourceManager.getString(R.string.core_error_no_connection) } returns noInternet every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong - every { appUpgradeNotifier.notifier } returns emptyFlow() + every { appNotifier.notifier } returns emptyFlow() every { config.getApiHostURL() } returns "http://localhost:8000" } @@ -84,7 +84,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } throws UnknownHostException() @@ -92,7 +92,7 @@ class DashboardViewModelTest { coVerify(exactly = 1) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage assertEquals(noInternet, message?.message) @@ -108,7 +108,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } throws Exception() @@ -116,7 +116,7 @@ class DashboardViewModelTest { coVerify(exactly = 1) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage assertEquals(somethingWrong, message?.message) @@ -132,7 +132,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList @@ -141,7 +141,7 @@ class DashboardViewModelTest { coVerify(exactly = 1) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assert(viewModel.uiMessage.value == null) assert(viewModel.uiState.value is DashboardUIState.Courses) @@ -156,7 +156,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList.copy( @@ -173,7 +173,7 @@ class DashboardViewModelTest { coVerify(exactly = 1) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assert(viewModel.uiMessage.value == null) assert(viewModel.uiState.value is DashboardUIState.Courses) @@ -190,14 +190,14 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) advanceUntilIdle() coVerify(exactly = 0) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 1) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assert(viewModel.uiMessage.value == null) assert(viewModel.uiState.value is DashboardUIState.Courses) @@ -214,7 +214,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) coEvery { interactor.getEnrolledCourses(any()) } throws UnknownHostException() @@ -223,7 +223,7 @@ class DashboardViewModelTest { coVerify(exactly = 2) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage assertEquals(noInternet, message?.message) @@ -242,7 +242,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) coEvery { interactor.getEnrolledCourses(any()) } throws Exception() @@ -251,7 +251,7 @@ class DashboardViewModelTest { coVerify(exactly = 2) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage assertEquals(somethingWrong, message?.message) @@ -270,7 +270,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) viewModel.updateCourses() @@ -278,7 +278,7 @@ class DashboardViewModelTest { coVerify(exactly = 2) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assert(viewModel.uiMessage.value == null) assert(viewModel.updating.value == false) @@ -303,7 +303,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) viewModel.updateCourses() @@ -311,7 +311,7 @@ class DashboardViewModelTest { coVerify(exactly = 2) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } assert(viewModel.uiMessage.value == null) assert(viewModel.updating.value == false) @@ -328,7 +328,7 @@ class DashboardViewModelTest { resourceManager, discoveryNotifier, analytics, - appUpgradeNotifier + appNotifier ) val mockLifeCycleOwner: LifecycleOwner = mockk() @@ -339,7 +339,7 @@ class DashboardViewModelTest { advanceUntilIdle() coVerify(exactly = 1) { interactor.getEnrolledCourses(any()) } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } } } diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryFragment.kt b/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryFragment.kt index ee99a5bb3..3a50ab707 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryFragment.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryFragment.kt @@ -63,7 +63,7 @@ import org.openedx.core.UIMessage import org.openedx.core.domain.model.Media import org.openedx.core.presentation.dialog.appupgrade.AppUpgradeDialogFragment import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRecommendedBox -import org.openedx.core.system.notifier.AppUpgradeEvent +import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.core.ui.AuthButtonsPanel import org.openedx.core.ui.BackBtn import org.openedx.core.ui.HandleUIMessage diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryViewModel.kt b/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryViewModel.kt index 271e05535..3f1098433 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryViewModel.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/NativeDiscoveryViewModel.kt @@ -15,8 +15,8 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.extension.isInternetError import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.AppUpgradeEvent -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.discovery.domain.interactor.DiscoveryInteractor import org.openedx.discovery.domain.model.Course @@ -26,7 +26,7 @@ class NativeDiscoveryViewModel( private val interactor: DiscoveryInteractor, private val resourceManager: ResourceManager, private val analytics: DiscoveryAnalytics, - private val appUpgradeNotifier: AppUpgradeNotifier, + private val appNotifier: AppNotifier, private val corePreferences: CorePreferences, ) : BaseViewModel() { @@ -160,14 +160,13 @@ class NativeDiscoveryViewModel( @OptIn(FlowPreview::class) private fun collectAppUpgradeEvent() { viewModelScope.launch { - appUpgradeNotifier.notifier + appNotifier.notifier .debounce(100) .collect { event -> when (event) { is AppUpgradeEvent.UpgradeRecommendedEvent -> { _appUpgradeEvent.value = event } - is AppUpgradeEvent.UpgradeRequiredEvent -> { _appUpgradeEvent.value = AppUpgradeEvent.UpgradeRequiredEvent } diff --git a/discovery/src/test/java/org/openedx/discovery/presentation/NativeDiscoveryViewModelTest.kt b/discovery/src/test/java/org/openedx/discovery/presentation/NativeDiscoveryViewModelTest.kt index 898a227c3..7360ef131 100644 --- a/discovery/src/test/java/org/openedx/discovery/presentation/NativeDiscoveryViewModelTest.kt +++ b/discovery/src/test/java/org/openedx/discovery/presentation/NativeDiscoveryViewModelTest.kt @@ -27,7 +27,7 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.Pagination import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.discovery.domain.interactor.DiscoveryInteractor import org.openedx.discovery.domain.model.CourseList import java.net.UnknownHostException @@ -46,7 +46,7 @@ class NativeDiscoveryViewModelTest { private val interactor = mockk() private val networkConnection = mockk() private val analytics = mockk() - private val appUpgradeNotifier = mockk() + private val appNotifier = mockk() private val corePreferences = mockk() private val noInternet = "Slow or no internet connection" @@ -57,7 +57,7 @@ class NativeDiscoveryViewModelTest { Dispatchers.setMain(dispatcher) every { resourceManager.getString(R.string.core_error_no_connection) } returns noInternet every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong - every { appUpgradeNotifier.notifier } returns emptyFlow() + every { appNotifier.notifier } returns emptyFlow() every { corePreferences.user } returns null every { config.getApiHostURL() } returns "http://localhost:8000" every { config.isPreLoginExperienceEnabled() } returns false @@ -76,7 +76,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true @@ -85,7 +85,7 @@ class NativeDiscoveryViewModelTest { coVerify(exactly = 1) { interactor.getCoursesList(any(), any(), any()) } coVerify(exactly = 0) { interactor.getCoursesListFromCache() } - verify(exactly = 1) { appUpgradeNotifier.notifier } + verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage assertEquals(noInternet, message?.message) @@ -101,7 +101,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true @@ -125,7 +125,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns false @@ -148,7 +148,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true @@ -178,7 +178,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true @@ -209,7 +209,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true @@ -234,7 +234,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true @@ -259,7 +259,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true @@ -290,7 +290,7 @@ class NativeDiscoveryViewModelTest { interactor, resourceManager, analytics, - appUpgradeNotifier, + appNotifier, corePreferences ) every { networkConnection.isOnline() } returns true diff --git a/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt b/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt index 75a780d72..4d0343d69 100644 --- a/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt +++ b/discussion/src/main/java/org/openedx/discussion/data/api/DiscussionApi.kt @@ -1,5 +1,6 @@ package org.openedx.discussion.data.api +import org.json.JSONObject import org.openedx.core.data.model.BlocksCompletionBody import org.openedx.discussion.data.model.request.* import org.openedx.discussion.data.model.response.CommentResult @@ -50,11 +51,11 @@ interface DiscussionApi { @Query("requested_fields") requestedFields: List = listOf("profile_image") ): CommentsResponse - @GET("/api/discussion/v1/comments/{comment_id}") - suspend fun getThreadComment( - @Path("comment_id") commentId: String, - @Query("requested_fields") requestedFields: List = listOf("profile_image") - ): CommentsResponse + @Headers("Content-type: application/merge-patch+json") + @PATCH("/api/discussion/v1/comments/{response_id}/") + suspend fun getResponse( + @Path("response_id") responseId: String + ): CommentResult @GET("/api/discussion/v1/comments/") suspend fun getThreadQuestionComments( diff --git a/discussion/src/main/java/org/openedx/discussion/data/model/response/CommentsResponse.kt b/discussion/src/main/java/org/openedx/discussion/data/model/response/CommentsResponse.kt index a2248b036..711bab32c 100644 --- a/discussion/src/main/java/org/openedx/discussion/data/model/response/CommentsResponse.kt +++ b/discussion/src/main/java/org/openedx/discussion/data/model/response/CommentsResponse.kt @@ -76,9 +76,9 @@ data class CommentResult( authorLabel ?: "", createdAt, updatedAt, - rawBody, - renderedBody, - TextConverter.textToLinkedImageText(renderedBody), + rawBody ?: "", + renderedBody ?: "", + TextConverter.textToLinkedImageText(renderedBody ?: ""), abuseFlagged, voted, voteCount, diff --git a/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt b/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt index 3ee4f74a5..95c603cf5 100644 --- a/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt +++ b/discussion/src/main/java/org/openedx/discussion/data/repository/DiscussionRepository.kt @@ -12,6 +12,7 @@ import org.openedx.discussion.data.model.request.ReportBody import org.openedx.discussion.data.model.request.ThreadBody import org.openedx.discussion.data.model.request.VoteBody import org.openedx.discussion.domain.model.CommentsData +import org.openedx.discussion.domain.model.DiscussionComment import org.openedx.discussion.domain.model.ThreadsData import org.openedx.discussion.domain.model.Topic @@ -81,10 +82,10 @@ class DiscussionRepository( return api.getThreadComments(threadId, page).mapToDomain() } - suspend fun getThreadComment( - commentId: String - ): CommentsData { - return api.getThreadComment(commentId).mapToDomain() + suspend fun getResponse( + responseId: String + ): DiscussionComment { + return api.getResponse(responseId).mapToDomain() } suspend fun getThreadQuestionComments( diff --git a/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt b/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt index 561a75006..90960011c 100644 --- a/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt +++ b/discussion/src/main/java/org/openedx/discussion/domain/interactor/DiscussionInteractor.kt @@ -2,6 +2,7 @@ package org.openedx.discussion.domain.interactor import org.openedx.discussion.data.repository.DiscussionRepository import org.openedx.discussion.domain.model.CommentsData +import org.openedx.discussion.domain.model.DiscussionComment class DiscussionInteractor( private val repository: DiscussionRepository @@ -41,8 +42,8 @@ class DiscussionInteractor( suspend fun getThreadComments(threadId: String, page: Int) = repository.getThreadComments(threadId, page) - suspend fun getThreadComment(commentId: String): CommentsData = - repository.getThreadComment(commentId) + suspend fun getResponse(responseId: String): DiscussionComment = + repository.getResponse(responseId) suspend fun getThreadQuestionComments(threadId: String, endorsed: Boolean, page: Int) = repository.getThreadQuestionComments(threadId, endorsed, page) diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt index f94064d30..5e044ca46 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt @@ -53,7 +53,7 @@ import androidx.compose.ui.window.Dialog import org.openedx.core.R import org.openedx.core.domain.model.AgreementUrls import org.openedx.core.presentation.global.AppData -import org.openedx.core.system.notifier.AppUpgradeEvent +import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.core.ui.OpenEdXButton import org.openedx.core.ui.Toolbar import org.openedx.core.ui.WindowSize diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt index 9715eb774..6e622e2cc 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt @@ -23,8 +23,9 @@ import org.openedx.core.module.DownloadWorkerController import org.openedx.core.presentation.global.AppData import org.openedx.core.system.AppCookieManager import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.AppUpgradeEvent -import org.openedx.core.system.notifier.AppUpgradeNotifier +import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent +import org.openedx.core.system.notifier.app.LogoutEvent import org.openedx.core.utils.EmailUtil import org.openedx.profile.domain.interactor.ProfileInteractor import org.openedx.profile.domain.model.Configuration @@ -44,7 +45,7 @@ class SettingsViewModel( private val workerController: DownloadWorkerController, private val analytics: ProfileAnalytics, private val router: ProfileRouter, - private val appUpgradeNotifier: AppUpgradeNotifier, + private val appNotifier: AppNotifier, private val profileNotifier: ProfileNotifier, ) : BaseViewModel() { @@ -100,6 +101,7 @@ class SettingsViewModel( } } finally { cookieManager.clearWebViewCookie() + appNotifier.send(LogoutEvent(false)) _successLogout.emit(true) } } @@ -107,8 +109,10 @@ class SettingsViewModel( private fun collectAppUpgradeEvent() { viewModelScope.launch { - appUpgradeNotifier.notifier.collect { event -> - _appUpgradeEvent.value = event + appNotifier.notifier.collect { event -> + if (event is AppUpgradeEvent) { + _appUpgradeEvent.value = event + } } } } From 5abf44d32cda055b62271fe5b83b838ac170d9c3 Mon Sep 17 00:00:00 2001 From: Omer Habib <30689349+omerhabib26@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:21:21 +0500 Subject: [PATCH 24/38] fix: update keyboard visibility and imeAction (#350) * fix: update keyboard visibility and imeAction - Hide keyboard on logistration screens - update imeAction for long InputEditFields -LEARNER-10032 * fix: Added error Text for editable fields on SignIn Screen - Add error text in case of empty fields on sign in Screen fix: LEARNER-10032 * fix: Address PR comments --- .../restore/RestorePasswordFragment.kt | 28 ++++++++--- .../presentation/signin/compose/SignInView.kt | 46 +++++++++++++++++-- .../presentation/signup/compose/SignUpView.kt | 7 ++- .../openedx/auth/presentation/ui/AuthUI.kt | 32 +++++++++---- auth/src/main/res/values/strings.xml | 3 ++ .../threads/DiscussionAddThreadFragment.kt | 2 +- .../presentation/edit/EditProfileFragment.kt | 2 +- 7 files changed, 97 insertions(+), 23 deletions(-) diff --git a/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt b/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt index 18cf169bc..84d2d584e 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource @@ -127,9 +128,9 @@ private fun RestorePasswordScreen( ) { val scaffoldState = rememberScaffoldState() val scrollState = rememberScrollState() - var email by rememberSaveable { - mutableStateOf("") - } + var email by rememberSaveable { mutableStateOf("") } + var isEmailError by rememberSaveable { mutableStateOf(false) } + val keyboardController = LocalSoftwareKeyboardController.current Scaffold( scaffoldState = scaffoldState, @@ -269,12 +270,20 @@ private fun RestorePasswordScreen( description = stringResource(id = authR.string.auth_example_email), onValueChanged = { email = it + isEmailError = false }, imeAction = ImeAction.Done, keyboardActions = { - it.clearFocus() - onRestoreButtonClick(email) - } + keyboardController?.hide() + if (email.isNotEmpty()) { + it.clearFocus() + onRestoreButtonClick(email) + } else { + isEmailError = email.isEmpty() + } + }, + isError = isEmailError, + errorMessages = stringResource(id = authR.string.auth_error_empty_email) ) Spacer(Modifier.height(50.dp)) if (uiState == RestorePasswordUIState.Loading) { @@ -292,7 +301,12 @@ private fun RestorePasswordScreen( modifier = buttonWidth.testTag("btn_reset_password"), text = stringResource(id = authR.string.auth_reset_password), onClick = { - onRestoreButtonClick(email) + keyboardController?.hide() + if (email.isNotEmpty()) { + onRestoreButtonClick(email) + } else { + isEmailError = email.isEmpty() + } } ) } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index 783a60a99..cb77faa37 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -220,6 +221,9 @@ private fun AuthForm( ) { var login by rememberSaveable { mutableStateOf("") } var password by rememberSaveable { mutableStateOf("") } + val keyboardController = LocalSoftwareKeyboardController.current + var isEmailError by rememberSaveable { mutableStateOf(false) } + var isPasswordError by rememberSaveable { mutableStateOf(false) } Column(horizontalAlignment = Alignment.CenterHorizontally) { LoginTextField( @@ -229,7 +233,11 @@ private fun AuthForm( description = stringResource(id = R.string.auth_enter_email_username), onValueChanged = { login = it - }) + isEmailError = false + }, + isError = isEmailError, + errorMessages = stringResource(id = R.string.auth_error_empty_username_email) + ) Spacer(modifier = Modifier.height(18.dp)) PasswordTextField( @@ -237,10 +245,18 @@ private fun AuthForm( .fillMaxWidth(), onValueChanged = { password = it + isPasswordError = false }, onPressDone = { - onEvent(AuthEvent.SignIn(login = login, password = password)) - } + keyboardController?.hide() + if (password.isNotEmpty()) { + onEvent(AuthEvent.SignIn(login = login, password = password)) + } else { + isEmailError = login.isEmpty() + isPasswordError = password.isEmpty() + } + }, + isError = isPasswordError, ) Row( @@ -282,7 +298,13 @@ private fun AuthForm( textColor = MaterialTheme.appColors.primaryButtonText, backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, onClick = { - onEvent(AuthEvent.SignIn(login = login, password = password)) + keyboardController?.hide() + if (login.isNotEmpty() && password.isNotEmpty()) { + onEvent(AuthEvent.SignIn(login = login, password = password)) + } else { + isEmailError = login.isEmpty() + isPasswordError = password.isEmpty() + } } ) } @@ -294,6 +316,7 @@ private fun AuthForm( isMicrosoftAuthEnabled = state.isMicrosoftAuthEnabled, isSignIn = true, ) { + keyboardController?.hide() onEvent(AuthEvent.SocialSignIn(it)) } } @@ -303,6 +326,7 @@ private fun AuthForm( @Composable private fun PasswordTextField( modifier: Modifier = Modifier, + isError: Boolean, onValueChanged: (String) -> Unit, onPressDone: () -> Unit, ) { @@ -361,9 +385,21 @@ private fun PasswordTextField( focusManager.clearFocus() onPressDone() }, + isError = isError, textStyle = MaterialTheme.appTypography.bodyMedium, - singleLine = true + singleLine = true, ) + if (isError) { + Text( + modifier = Modifier + .testTag("txt_password_error") + .fillMaxWidth() + .padding(top = 4.dp), + text = stringResource(id = R.string.auth_error_empty_password), + style = MaterialTheme.appTypography.bodySmall, + color = MaterialTheme.appColors.error, + ) + } } @Preview(uiMode = UI_MODE_NIGHT_NO) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt index 2872c579b..e1e31c7b8 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt @@ -442,6 +442,7 @@ internal fun SignUpView( textColor = MaterialTheme.appColors.primaryButtonText, backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, onClick = { + keyboardController?.hide() showErrorMap.clear() onRegisterClick(AuthType.PASSWORD) } @@ -455,6 +456,7 @@ internal fun SignUpView( isMicrosoftAuthEnabled = uiState.isMicrosoftAuthEnabled, isSignIn = false, ) { + keyboardController?.hide() onRegisterClick(it) } } @@ -478,7 +480,10 @@ private fun RegistrationScreenPreview() { SignUpView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), uiState = SignUpUIState( - allFields = listOf(field, field, field.copy(required = false)), + allFields = listOf(field), + requiredFields = listOf(field, field), + optionalFields = listOf(field, field), + agreementFields = listOf(field), ), uiMessage = null, onBackClick = {}, diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt index 16d75492b..9f75a2478 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -69,14 +70,15 @@ fun RequiredFields( showErrorMap: MutableMap, selectableNamesMap: MutableMap, onFieldUpdated: (String, String) -> Unit, - onSelectClick: (String, RegistrationField, List) -> Unit + onSelectClick: (String, RegistrationField, List) -> Unit, ) { fields.forEach { field -> when (field.type) { RegistrationFieldType.TEXT, RegistrationFieldType.EMAIL, RegistrationFieldType.CONFIRM_EMAIL, - RegistrationFieldType.PASSWORD -> { + RegistrationFieldType.PASSWORD, + -> { InputRegistrationField( modifier = Modifier.fillMaxWidth(), isErrorShown = showErrorMap[field.name] ?: true, @@ -232,9 +234,11 @@ fun LoginTextField( modifier: Modifier = Modifier, title: String, description: String, + isError: Boolean = false, + errorMessages: String = "", onValueChanged: (String) -> Unit, imeAction: ImeAction = ImeAction.Next, - keyboardActions: (FocusManager) -> Unit = { it.moveFocus(FocusDirection.Down) } + keyboardActions: (FocusManager) -> Unit = { it.moveFocus(FocusDirection.Down) }, ) { var loginTextFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf( @@ -281,8 +285,20 @@ fun LoginTextField( }, textStyle = MaterialTheme.appTypography.bodyMedium, singleLine = true, - modifier = modifier.testTag("tf_email") + modifier = modifier.testTag("tf_email"), + isError = isError ) + if (isError) { + Text( + modifier = Modifier + .testTag("txt_email_error") + .fillMaxWidth() + .padding(top = 4.dp), + text = errorMessages, + style = MaterialTheme.appTypography.bodySmall, + color = MaterialTheme.appColors.error, + ) + } } @Composable @@ -290,7 +306,7 @@ fun InputRegistrationField( modifier: Modifier, isErrorShown: Boolean, registrationField: RegistrationField, - onValueChanged: (String, String, Boolean) -> Unit + onValueChanged: (String, String, Boolean) -> Unit, ) { var inputRegistrationFieldValue by rememberSaveable { mutableStateOf(registrationField.placeholder) @@ -401,7 +417,7 @@ fun SelectableRegisterField( registrationField: RegistrationField, isErrorShown: Boolean, initialValue: String, - onClick: (String, List) -> Unit + onClick: (String, List) -> Unit, ) { val helperTextColor = if (registrationField.errorInstructions.isEmpty()) { MaterialTheme.appColors.textSecondary @@ -489,7 +505,7 @@ fun SelectableRegisterField( fun ExpandableText( modifier: Modifier = Modifier, isExpanded: Boolean, - onClick: (Boolean) -> Unit + onClick: (Boolean) -> Unit, ) { val transitionState = remember { MutableTransitionState(isExpanded).apply { @@ -537,7 +553,7 @@ fun ExpandableText( @Composable internal fun PasswordVisibilityIcon( isPasswordVisible: Boolean, - onClick: () -> Unit + onClick: () -> Unit, ) { val (image, description) = if (isPasswordVisible) { Icons.Filled.VisibilityOff to stringResource(R.string.auth_accessibility_hide_password) diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 642185915..49a8fb68e 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -22,7 +22,10 @@ We have sent a password recover instructions to your email %s username@domain.com Enter email or username + Please enter your username or e-mail address and try again. + Please enter your e-mail address and try again. Enter password + Please enter your password and try again. Create an account to start learning today! Complete your registration Sign in with Google diff --git a/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionAddThreadFragment.kt b/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionAddThreadFragment.kt index 416140f1e..a211e10b3 100644 --- a/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionAddThreadFragment.kt +++ b/discussion/src/main/java/org/openedx/discussion/presentation/threads/DiscussionAddThreadFragment.kt @@ -395,7 +395,7 @@ private fun DiscussionAddThreadScreen( ), isSingleLine = false, withRequiredMark = true, - imeAction = ImeAction.Done, + imeAction = ImeAction.Default, keyboardActions = { focusManager -> focusManager.clearFocus() keyboardController?.hide() diff --git a/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt index 5fc9e9a78..3800d23ac 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileFragment.kt @@ -1047,7 +1047,7 @@ private fun InputEditField( }, keyboardOptions = KeyboardOptions.Default.copy( keyboardType = keyboardType, - imeAction = ImeAction.Done + imeAction = ImeAction.Default ), keyboardActions = KeyboardActions { keyboardController?.hide() From ba305a09c6e09a9806bea389155b937b756d6c69 Mon Sep 17 00:00:00 2001 From: Igor Date: Mon, 8 Jul 2024 12:27:54 +0200 Subject: [PATCH 25/38] fix: show only one screen with all downloadable content (#352) --- .../outline/CourseOutlineViewModel.kt | 17 ++++++++++------- .../openedx/course/presentation/ui/CourseUI.kt | 3 +-- .../presentation/videos/CourseVideoViewModel.kt | 17 ++++++++++------- 3 files changed, 21 insertions(+), 16 deletions(-) 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 6ea080957..b65b3b62a 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 @@ -388,14 +388,17 @@ class CourseOutlineViewModel( } } - fun downloadBlocks(blocksIds: List, fragmentManager: FragmentManager, context: Context) { + fun downloadBlocks( + blocksIds: List, + fragmentManager: FragmentManager, + context: Context + ) { + if (blocksIds.find { isBlockDownloading(it) } != null) { + courseRouter.navigateToDownloadQueue(fm = fragmentManager) + return + } blocksIds.forEach { blockId -> - if (isBlockDownloading(blockId)) { - courseRouter.navigateToDownloadQueue( - fm = fragmentManager, - getDownloadableChildren(blockId) ?: arrayListOf() - ) - } else if (isBlockDownloaded(blockId)) { + if (isBlockDownloaded(blockId)) { removeDownloadModels(blockId) } else { saveDownloadModels( 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 c187af0ad..7135bb8c6 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 @@ -244,8 +244,7 @@ fun OfflineQueueCard( maxLines = 1 ) - val progress = progressValue.toFloat() / progressSize - + val progress = if (progressSize == 0L) 0f else progressValue.toFloat() / progressSize LinearProgressIndicator( modifier = Modifier .fillMaxWidth() diff --git a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt index 49f3b6120..a5bf069cd 100644 --- a/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt @@ -214,14 +214,17 @@ class CourseVideoViewModel( return resultBlocks.toList() } - fun downloadBlocks(blocksIds: List, fragmentManager: FragmentManager, context: Context) { + fun downloadBlocks( + blocksIds: List, + fragmentManager: FragmentManager, + context: Context + ) { + if (blocksIds.find { isBlockDownloading(it) } != null) { + courseRouter.navigateToDownloadQueue(fm = fragmentManager) + return + } blocksIds.forEach { blockId -> - if (isBlockDownloading(blockId)) { - courseRouter.navigateToDownloadQueue( - fm = fragmentManager, - getDownloadableChildren(blockId) ?: arrayListOf() - ) - } else if (isBlockDownloaded(blockId)) { + if (isBlockDownloaded(blockId)) { removeDownloadModels(blockId) } else { saveDownloadModels( From 02a83ede97c7cb4c8b2fa0e0e25416229039daf9 Mon Sep 17 00:00:00 2001 From: Hamza Israr <71447999+HamzaIsrar12@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:29:02 +0500 Subject: [PATCH 26/38] fix: Video Subtitles on Native and Youtube Player (#349) * fix: Video Subtitles on Native and Youtube Player * chore: UI Changes --- .../java/org/openedx/course/presentation/ui/CourseUI.kt | 9 ++++++++- .../course/presentation/unit/video/VideoUnitFragment.kt | 1 - .../course/presentation/unit/video/VideoUnitViewModel.kt | 2 +- .../course/presentation/unit/video/VideoViewModel.kt | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) 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 7135bb8c6..b111dd1f0 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 @@ -69,6 +69,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow @@ -562,6 +563,11 @@ fun VideoSubtitles( } else { MaterialTheme.appColors.textFieldBorder } + val fontWeight = if (currentIndex == index) { + FontWeight.SemiBold + } else { + FontWeight.Normal + } Text( modifier = Modifier .fillMaxWidth() @@ -570,7 +576,8 @@ fun VideoSubtitles( }, text = Jsoup.parse(item.content).text(), color = textColor, - style = MaterialTheme.appTypography.bodyMedium + style = MaterialTheme.appTypography.bodyMedium, + fontWeight = fontWeight, ) Spacer(Modifier.height(16.dp)) } diff --git a/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitFragment.kt b/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitFragment.kt index 2e078f4c6..d92b3b067 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitFragment.kt @@ -91,7 +91,6 @@ class VideoUnitFragment : Fragment(R.layout.fragment_video_unit) { viewModel.isDownloaded = getBoolean(ARG_DOWNLOADED) } viewModel.downloadSubtitles() - handler.removeCallbacks(videoTimeRunnable) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitViewModel.kt b/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitViewModel.kt index e28e723f6..5779b96da 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/video/VideoUnitViewModel.kt @@ -100,8 +100,8 @@ open class VideoUnitViewModel( open fun markBlockCompleted(blockId: String, medium: String) { - logLoadedCompletedEvent(videoUrl, false, getCurrentVideoTime(), medium) if (!isBlockAlreadyCompleted) { + logLoadedCompletedEvent(videoUrl, false, getCurrentVideoTime(), medium) viewModelScope.launch { try { isBlockAlreadyCompleted = true diff --git a/course/src/main/java/org/openedx/course/presentation/unit/video/VideoViewModel.kt b/course/src/main/java/org/openedx/course/presentation/unit/video/VideoViewModel.kt index a4063393a..4ae600eb8 100644 --- a/course/src/main/java/org/openedx/course/presentation/unit/video/VideoViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/unit/video/VideoViewModel.kt @@ -40,8 +40,8 @@ class VideoViewModel( } fun markBlockCompleted(blockId: String, medium: String) { - logLoadedCompletedEvent(videoUrl, false, currentVideoTime, medium) if (!isBlockAlreadyCompleted) { + logLoadedCompletedEvent(videoUrl, false, currentVideoTime, medium) viewModelScope.launch { try { isBlockAlreadyCompleted = true From 9f0740fa4f64f4e27a3f1d92af6a45bdb6cd1e1c Mon Sep 17 00:00:00 2001 From: Hamza Israr <71447999+HamzaIsrar12@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:34:28 +0500 Subject: [PATCH 27/38] feat: Handle Branch Deeplinks from Braze Push Notification (#353) * feat: Handle Branch Deeplinks from Braze Push Notification Fixes: LEARNER-10054 * refactor: Update class name to BranchBrazeDeeplinkHandler --- .../main/java/org/openedx/app/AppActivity.kt | 39 +++++++++---------- .../main/java/org/openedx/app/OpenEdXApp.kt | 7 ++++ .../deeplink/BranchBrazeDeeplinkHandler.kt | 26 +++++++++++++ 3 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/org/openedx/app/deeplink/BranchBrazeDeeplinkHandler.kt diff --git a/app/src/main/java/org/openedx/app/AppActivity.kt b/app/src/main/java/org/openedx/app/AppActivity.kt index c8d4c9259..e03d9f2cd 100644 --- a/app/src/main/java/org/openedx/app/AppActivity.kt +++ b/app/src/main/java/org/openedx/app/AppActivity.kt @@ -59,6 +59,20 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder { private var _windowSize = WindowSize(WindowType.Compact, WindowType.Compact) + private val branchCallback = + BranchUniversalReferralInitListener { branchUniversalObject, _, error -> + if (branchUniversalObject?.contentMetadata?.customMetadata != null) { + branchLogger.i { "Branch init complete." } + branchLogger.i { branchUniversalObject.contentMetadata.customMetadata.toString() } + viewModel.makeExternalRoute( + fm = supportFragmentManager, + deepLink = DeepLink(branchUniversalObject.contentMetadata.customMetadata) + ) + } else if (error != null) { + branchLogger.e { "Branch init failed. Caused by -" + error.message } + } + } + override fun onSaveInstanceState(outState: Bundle) { outState.putInt(TOP_INSET, topInset) outState.putInt(BOTTOM_INSET, bottomInset) @@ -152,21 +166,8 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder { super.onStart() if (viewModel.isBranchEnabled) { - val callback = BranchUniversalReferralInitListener { branchUniversalObject, _, error -> - if (branchUniversalObject?.contentMetadata?.customMetadata != null) { - branchLogger.i { "Branch init complete." } - branchLogger.i { branchUniversalObject.contentMetadata.customMetadata.toString() } - viewModel.makeExternalRoute( - fm = supportFragmentManager, - deepLink = DeepLink(branchUniversalObject.contentMetadata.customMetadata) - ) - } else if (error != null) { - branchLogger.e { "Branch init failed. Caused by -" + error.message } - } - } - Branch.sessionBuilder(this) - .withCallback(callback) + .withCallback(branchCallback) .withData(this.intent.data) .init() } @@ -183,13 +184,9 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder { if (viewModel.isBranchEnabled) { if (intent?.getBooleanExtra(BRANCH_FORCE_NEW_SESSION, false) == true) { - Branch.sessionBuilder(this).withCallback { referringParams, error -> - if (error != null) { - branchLogger.e { error.message } - } else if (referringParams != null) { - branchLogger.i { referringParams.toString() } - } - }.reInit() + Branch.sessionBuilder(this) + .withCallback(branchCallback) + .reInit() } } } diff --git a/app/src/main/java/org/openedx/app/OpenEdXApp.kt b/app/src/main/java/org/openedx/app/OpenEdXApp.kt index 7d1b81d32..ccf20d5b2 100644 --- a/app/src/main/java/org/openedx/app/OpenEdXApp.kt +++ b/app/src/main/java/org/openedx/app/OpenEdXApp.kt @@ -3,11 +3,13 @@ package org.openedx.app import android.app.Application import com.braze.Braze import com.braze.configuration.BrazeConfig +import com.braze.ui.BrazeDeeplinkHandler import com.google.firebase.FirebaseApp import io.branch.referral.Branch import org.koin.android.ext.android.inject import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin +import org.openedx.app.deeplink.BranchBrazeDeeplinkHandler import org.openedx.app.di.appModule import org.openedx.app.di.networkingModule import org.openedx.app.di.screenModule @@ -36,6 +38,7 @@ class OpenEdXApp : Application() { Branch.enableTestMode() Branch.enableLogging() } + Branch.expectDelayedSessionInitialization(true) Branch.getAutoInstance(this) } @@ -50,6 +53,10 @@ class OpenEdXApp : Application() { .setIsFirebaseMessagingServiceOnNewTokenRegistrationEnabled(true) .build() Braze.configure(this, brazeConfig) + + if (config.getBranchConfig().enabled) { + BrazeDeeplinkHandler.setBrazeDeeplinkHandler(BranchBrazeDeeplinkHandler()) + } } } } diff --git a/app/src/main/java/org/openedx/app/deeplink/BranchBrazeDeeplinkHandler.kt b/app/src/main/java/org/openedx/app/deeplink/BranchBrazeDeeplinkHandler.kt new file mode 100644 index 000000000..967c3768b --- /dev/null +++ b/app/src/main/java/org/openedx/app/deeplink/BranchBrazeDeeplinkHandler.kt @@ -0,0 +1,26 @@ +package org.openedx.app.deeplink + +import android.content.Context +import android.content.Intent +import android.net.Uri +import com.braze.ui.BrazeDeeplinkHandler +import com.braze.ui.actions.UriAction +import org.openedx.app.AppActivity + +internal class BranchBrazeDeeplinkHandler : BrazeDeeplinkHandler() { + override fun gotoUri(context: Context, uriAction: UriAction) { + val deeplink = uriAction.uri.toString() + + if (deeplink.contains("app.link")) { + val intent = Intent(context, AppActivity::class.java).apply { + action = Intent.ACTION_VIEW + data = Uri.parse(deeplink) + flags = Intent.FLAG_ACTIVITY_NEW_TASK + putExtra("branch_force_new_session", true) + } + context.startActivity(intent) + } else { + super.gotoUri(context, uriAction) + } + } +} From 6efdd76c62f07acbc404db377c43cba67a8e8caa Mon Sep 17 00:00:00 2001 From: Hamza Israr <71447999+HamzaIsrar12@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:36:19 +0500 Subject: [PATCH 28/38] feat: Fullstory Analytics SDK Implementation (#347) * feat: Fullstory Analytics SDK Implementation We have introduced the Fullstory Analytics Provider, which includes three main methods: Identify: This method identifies the user by passing a userID (uid). Additionally, it includes a displayName for use on the Fullstory dashboard. Event: This method records custom app events. Page: This method functions similarly to a screen event, tracking page views. Fixes: LEARNER-10041 * feat: Add screen event method to the Analytics Manager Fixes: LEARNER-10041 * fix: Course Home Tabs Events Fixes: LEARNER-10041 * chore: Discovery Screen Events Fixes: LEARNER-10041 * chore: Main Dashboard Screen Events Fixes: LEARNER-10041 * chore: Auth Screen Events Fixes: LEARNER-10041 * chore: Profile Screen Events Fixes: LEARNER-10041 * chore: Course Screen Events Fixes: LEARNER-10041 * fix: PLS Banner Multiple Events Fixes: LEARNER-10041 * chore: Logistration Screen Event Fixes: LEARNER-10041 * refactor: Optimize code Fixes: LEARNER-10041 --- app/build.gradle | 16 ++++++++ .../java/org/openedx/app/AnalyticsManager.kt | 12 ++++++ .../main/java/org/openedx/app/AppAnalytics.kt | 9 +--- .../main/java/org/openedx/app/MainFragment.kt | 1 - .../java/org/openedx/app/MainViewModel.kt | 16 +++----- .../app/analytics/FirebaseAnalytics.kt | 1 + .../app/analytics/FullstoryAnalytics.kt | 41 +++++++++++++++++++ .../java/org/openedx/app/di/ScreenModule.kt | 2 +- .../auth/presentation/AuthAnalytics.kt | 13 ++++++ .../logistration/LogistrationViewModel.kt | 14 +++++++ .../presentation/signin/SignInViewModel.kt | 11 +++++ .../presentation/signup/SignUpViewModel.kt | 11 +++++ .../signin/SignInViewModelTest.kt | 7 ++++ .../signup/SignUpViewModelTest.kt | 5 +++ core/build.gradle | 4 ++ .../java/org/openedx/core/config/Config.kt | 5 +++ .../openedx/core/config/FullstoryConfig.kt | 11 +++++ .../java/org/openedx/core/ui/ComposeCommon.kt | 2 +- .../course/presentation/CourseAnalytics.kt | 1 + .../container/CourseContainerViewModel.kt | 4 +- .../presentation/dates/CourseDatesScreen.kt | 13 +++++- .../handouts/HandoutsViewModel.kt | 4 +- .../container/CourseContainerViewModelTest.kt | 16 ++++---- .../presentation/DashboardAnalytics.kt | 16 ++++++++ .../learn/presentation/LearnFragment.kt | 11 +++++ .../learn/presentation/LearnViewModel.kt | 21 ++++++++++ default_config/dev/config.yaml | 4 ++ default_config/prod/config.yaml | 4 ++ default_config/stage/config.yaml | 4 ++ .../presentation/DiscoveryAnalytics.kt | 1 + .../presentation/WebViewDiscoveryViewModel.kt | 2 +- .../presentation/info/CourseInfoViewModel.kt | 33 ++++++++++----- .../profile/presentation/ProfileAnalytics.kt | 5 +++ .../presentation/edit/EditProfileViewModel.kt | 17 ++++++++ .../edit/EditProfileViewModelTest.kt | 2 + settings.gradle | 4 ++ 36 files changed, 297 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/org/openedx/app/analytics/FullstoryAnalytics.kt create mode 100644 core/src/main/java/org/openedx/core/config/FullstoryConfig.kt diff --git a/app/build.gradle b/app/build.gradle index e0992b266..659730ff0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,11 +3,15 @@ def appId = config.getOrDefault("APPLICATION_ID", "org.openedx.app") def themeDirectory = config.getOrDefault("THEME_DIRECTORY", "openedx") def firebaseConfig = config.get('FIREBASE') def firebaseEnabled = firebaseConfig?.getOrDefault('ENABLED', false) +def fullstoryConfig = config.get("FULLSTORY") +def fullstoryEnabled = fullstoryConfig?.getOrDefault('ENABLED', false) apply plugin: 'com.android.application' apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-kapt' +apply plugin: 'fullstory' + if (firebaseEnabled) { apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' @@ -25,6 +29,18 @@ if (firebaseEnabled) { preBuild.dependsOn(removeGoogleServicesJson) } +if (fullstoryEnabled) { + def fullstoryOrgId = fullstoryConfig?.get("ORG_ID") + + fullstory { + org fullstoryOrgId + composeEnabled true + composeSelectorVersion 4 + enabledVariants 'debug|release' + logcatLevel 'error' + } +} + android { compileSdk 34 diff --git a/app/src/main/java/org/openedx/app/AnalyticsManager.kt b/app/src/main/java/org/openedx/app/AnalyticsManager.kt index 356a23459..9d8169863 100644 --- a/app/src/main/java/org/openedx/app/AnalyticsManager.kt +++ b/app/src/main/java/org/openedx/app/AnalyticsManager.kt @@ -3,6 +3,7 @@ package org.openedx.app import android.content.Context import org.openedx.app.analytics.Analytics import org.openedx.app.analytics.FirebaseAnalytics +import org.openedx.app.analytics.FullstoryAnalytics import org.openedx.app.analytics.SegmentAnalytics import org.openedx.auth.presentation.AuthAnalytics import org.openedx.core.config.Config @@ -29,10 +30,15 @@ class AnalyticsManager( if (config.getFirebaseConfig().enabled) { addAnalyticsTracker(FirebaseAnalytics(context = context)) } + val segmentConfig = config.getSegmentConfig() if (segmentConfig.enabled && segmentConfig.segmentWriteKey.isNotBlank()) { addAnalyticsTracker(SegmentAnalytics(context = context, config = config)) } + + if (config.getFullstoryConfig().isEnabled) { + addAnalyticsTracker(FullstoryAnalytics()) + } } private fun addAnalyticsTracker(analytic: Analytics) { @@ -45,6 +51,12 @@ class AnalyticsManager( } } + override fun logScreenEvent(screenName: String, params: Map) { + services.forEach { analytics -> + analytics.logScreenEvent(screenName, params) + } + } + override fun logEvent(event: String, params: Map) { services.forEach { analytics -> analytics.logEvent(event, params) diff --git a/app/src/main/java/org/openedx/app/AppAnalytics.kt b/app/src/main/java/org/openedx/app/AppAnalytics.kt index 51278ef13..a122e79c1 100644 --- a/app/src/main/java/org/openedx/app/AppAnalytics.kt +++ b/app/src/main/java/org/openedx/app/AppAnalytics.kt @@ -4,6 +4,7 @@ interface AppAnalytics { fun logoutEvent(force: Boolean) fun setUserIdForSession(userId: Long) fun logEvent(event: String, params: Map) + fun logScreenEvent(screenName: String, params: Map) } enum class AppAnalyticsEvent(val eventName: String, val biValue: String) { @@ -15,14 +16,6 @@ enum class AppAnalyticsEvent(val eventName: String, val biValue: String) { "MainDashboard:Discover", "edx.bi.app.main_dashboard.discover" ), - MY_COURSES( - "MainDashboard:My Courses", - "edx.bi.app.main_dashboard.my_course" - ), - MY_PROGRAMS( - "MainDashboard:My Programs", - "edx.bi.app.main_dashboard.my_program" - ), PROFILE( "MainDashboard:Profile", "edx.bi.app.main_dashboard.profile" diff --git a/app/src/main/java/org/openedx/app/MainFragment.kt b/app/src/main/java/org/openedx/app/MainFragment.kt index 62857ee9f..4011b3a04 100644 --- a/app/src/main/java/org/openedx/app/MainFragment.kt +++ b/app/src/main/java/org/openedx/app/MainFragment.kt @@ -46,7 +46,6 @@ class MainFragment : Fragment(R.layout.fragment_main) { binding.bottomNavView.setOnItemSelectedListener { when (it.itemId) { R.id.fragmentLearn -> { - viewModel.logMyCoursesTabClickedEvent() binding.viewPager.setCurrentItem(0, false) } diff --git a/app/src/main/java/org/openedx/app/MainViewModel.kt b/app/src/main/java/org/openedx/app/MainViewModel.kt index f3d62c04f..5cef29361 100644 --- a/app/src/main/java/org/openedx/app/MainViewModel.kt +++ b/app/src/main/java/org/openedx/app/MainViewModel.kt @@ -14,7 +14,6 @@ import org.openedx.core.BaseViewModel import org.openedx.core.config.Config import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.core.system.notifier.NavigationToDiscovery -import org.openedx.dashboard.presentation.DashboardRouter import org.openedx.discovery.presentation.DiscoveryNavigator class MainViewModel( @@ -51,20 +50,17 @@ class MainViewModel( } fun logDiscoveryTabClickedEvent() { - logEvent(AppAnalyticsEvent.DISCOVER) - } - - fun logMyCoursesTabClickedEvent() { - logEvent(AppAnalyticsEvent.MY_COURSES) + logScreenEvent(AppAnalyticsEvent.DISCOVER) } fun logProfileTabClickedEvent() { - logEvent(AppAnalyticsEvent.PROFILE) + logScreenEvent(AppAnalyticsEvent.PROFILE) } - private fun logEvent(event: AppAnalyticsEvent) { - analytics.logEvent(event.eventName, - buildMap { + private fun logScreenEvent(event: AppAnalyticsEvent) { + analytics.logScreenEvent( + screenName = event.eventName, + params = buildMap { put(AppAnalyticsKey.NAME.key, event.biValue) } ) diff --git a/app/src/main/java/org/openedx/app/analytics/FirebaseAnalytics.kt b/app/src/main/java/org/openedx/app/analytics/FirebaseAnalytics.kt index 503f3d1ef..17d3b3b62 100644 --- a/app/src/main/java/org/openedx/app/analytics/FirebaseAnalytics.kt +++ b/app/src/main/java/org/openedx/app/analytics/FirebaseAnalytics.kt @@ -16,6 +16,7 @@ class FirebaseAnalytics(context: Context) : Analytics { } override fun logScreenEvent(screenName: String, params: Map) { + tracker.logEvent(screenName, params.toBundle()) logger.d { "Firebase Analytics log Screen Event: $screenName + $params" } } diff --git a/app/src/main/java/org/openedx/app/analytics/FullstoryAnalytics.kt b/app/src/main/java/org/openedx/app/analytics/FullstoryAnalytics.kt new file mode 100644 index 000000000..11aa26bc7 --- /dev/null +++ b/app/src/main/java/org/openedx/app/analytics/FullstoryAnalytics.kt @@ -0,0 +1,41 @@ +package org.openedx.app.analytics + +import com.fullstory.FS +import com.fullstory.FSSessionData +import org.openedx.core.utils.Logger + +class FullstoryAnalytics : Analytics { + + private val logger = Logger(TAG) + + init { + FS.setReadyListener { sessionData: FSSessionData -> + val sessionUrl = sessionData.currentSessionURL + logger.d { "FullStory Session URL is: $sessionUrl" } + } + } + + override fun logScreenEvent(screenName: String, params: Map) { + logger.d { "Page : $screenName $params" } + FS.page(screenName, params).start() + } + + override fun logEvent(eventName: String, params: Map) { + logger.d { "Event: $eventName $params" } + FS.page(eventName, params).start() + } + + override fun logUserId(userId: Long) { + logger.d { "Identify: $userId" } + FS.identify( + userId.toString(), mapOf( + DISPLAY_NAME to userId + ) + ) + } + + private companion object { + const val TAG = "FullstoryAnalytics" + private const val DISPLAY_NAME = "displayName" + } +} diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 3fb4667df..429d048b9 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -147,7 +147,7 @@ val screenModule = module { ) } viewModel { AllEnrolledCoursesViewModel(get(), get(), get(), get(), get(), get(), get()) } - viewModel { LearnViewModel(get(), get()) } + viewModel { LearnViewModel(get(), get(), get()) } factory { DiscoveryRepository(get(), get(), get()) } factory { DiscoveryInteractor(get()) } diff --git a/auth/src/main/java/org/openedx/auth/presentation/AuthAnalytics.kt b/auth/src/main/java/org/openedx/auth/presentation/AuthAnalytics.kt index e87ad9674..40125a18e 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/AuthAnalytics.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/AuthAnalytics.kt @@ -3,9 +3,14 @@ package org.openedx.auth.presentation interface AuthAnalytics { fun setUserIdForSession(userId: Long) fun logEvent(event: String, params: Map) + fun logScreenEvent(screenName: String, params: Map) } enum class AuthAnalyticsEvent(val eventName: String, val biValue: String) { + Logistration( + "Logistration", + "edx.bi.app.logistration" + ), DISCOVERY_COURSES_SEARCH( "Logistration:Courses Search", "edx.bi.app.logistration.courses_search" @@ -14,6 +19,14 @@ enum class AuthAnalyticsEvent(val eventName: String, val biValue: String) { "Logistration:Explore All Courses", "edx.bi.app.logistration.explore.all.courses" ), + SIGN_IN( + "Logistration:Sign In", + "edx.bi.app.logistration.signin" + ), + REGISTER( + "Logistration:Register", + "edx.bi.app.logistration.register" + ), REGISTER_CLICKED( "Logistration:Register Clicked", "edx.bi.app.logistration.register.clicked" diff --git a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationViewModel.kt index e48a5e8be..3306ccfa3 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationViewModel.kt @@ -18,6 +18,10 @@ class LogistrationViewModel( private val discoveryTypeWebView get() = config.getDiscoveryConfig().isViewTypeWebView() + init { + logLogistrationScreenEvent() + } + fun navigateToSignIn(parentFragmentManager: FragmentManager) { router.navigateToSignIn(parentFragmentManager, courseId, null) logEvent(AuthAnalyticsEvent.SIGN_IN_CLICKED) @@ -62,4 +66,14 @@ class LogistrationViewModel( } ) } + + private fun logLogistrationScreenEvent() { + val event = AuthAnalyticsEvent.Logistration + analytics.logScreenEvent( + screenName = event.eventName, + params = buildMap { + put(AuthAnalyticsKey.NAME.key, event.biValue) + } + ) + } } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt index 9fbd8c2fe..dd03bdaae 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt @@ -78,6 +78,7 @@ class SignInViewModel( init { collectAppUpgradeEvent() + logSignInScreenEvent() } fun login(username: String, password: String) { @@ -245,4 +246,14 @@ class SignInViewModel( } ) } + + private fun logSignInScreenEvent() { + val event = AuthAnalyticsEvent.SIGN_IN + analytics.logScreenEvent( + screenName = event.eventName, + params = buildMap { + put(AuthAnalyticsKey.NAME.key, event.biValue) + } + ) + } } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt index 42b6bf2d1..0826fca5c 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt @@ -73,6 +73,7 @@ class SignUpViewModel( init { collectAppUpgradeEvent() + logRegisterScreenEvent() } fun getRegistrationFields() { @@ -324,4 +325,14 @@ class SignUpViewModel( } ) } + + private fun logRegisterScreenEvent() { + val event = AuthAnalyticsEvent.REGISTER + analytics.logScreenEvent( + screenName = event.eventName, + params = buildMap { + put(AuthAnalyticsKey.NAME.key, event.biValue) + } + ) + } } diff --git a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt index d35e34040..a46b371c8 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt @@ -87,6 +87,7 @@ class SignInViewModelTest { every { config.getFacebookConfig() } returns FacebookConfig() every { config.getGoogleConfig() } returns GoogleConfig() every { config.getMicrosoftConfig() } returns MicrosoftConfig() + every { analytics.logScreenEvent(any(), any()) } returns Unit } @After @@ -119,6 +120,7 @@ class SignInViewModelTest { coVerify(exactly = 0) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } val message = viewModel.uiMessage.value as UIMessage.SnackBarMessage val uiState = viewModel.uiState.value @@ -220,6 +222,7 @@ class SignInViewModelTest { coVerify(exactly = 0) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } val message = viewModel.uiMessage.value as UIMessage.SnackBarMessage val uiState = viewModel.uiState.value @@ -258,6 +261,7 @@ class SignInViewModelTest { coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 1) { analytics.setUserIdForSession(any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } verify(exactly = 1) { appNotifier.notifier } val uiState = viewModel.uiState.value assertFalse(uiState.showProgress) @@ -294,6 +298,7 @@ class SignInViewModelTest { coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } verify(exactly = 1) { appNotifier.notifier } val message = viewModel.uiMessage.value as? UIMessage.SnackBarMessage @@ -333,6 +338,7 @@ class SignInViewModelTest { verify(exactly = 0) { analytics.setUserIdForSession(any()) } verify(exactly = 1) { appNotifier.notifier } verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } val message = viewModel.uiMessage.value as UIMessage.SnackBarMessage val uiState = viewModel.uiState.value @@ -371,6 +377,7 @@ class SignInViewModelTest { verify(exactly = 0) { analytics.setUserIdForSession(any()) } verify(exactly = 1) { appNotifier.notifier } verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } val message = viewModel.uiMessage.value as UIMessage.SnackBarMessage val uiState = viewModel.uiState.value diff --git a/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt index 5be80557c..f61e1053e 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt @@ -119,6 +119,7 @@ class SignUpViewModelTest { every { config.getGoogleConfig() } returns GoogleConfig() every { config.getMicrosoftConfig() } returns MicrosoftConfig() every { config.getMicrosoftConfig() } returns MicrosoftConfig() + every { analytics.logScreenEvent(any(), any()) } returns Unit } @After @@ -159,6 +160,7 @@ class SignUpViewModelTest { advanceUntilIdle() coVerify(exactly = 1) { interactor.validateRegistrationFields(any()) } verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } coVerify(exactly = 0) { interactor.register(any()) } coVerify(exactly = 0) { interactor.login(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } @@ -206,6 +208,7 @@ class SignUpViewModelTest { viewModel.register() advanceUntilIdle() verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } verify(exactly = 0) { analytics.setUserIdForSession(any()) } coVerify(exactly = 1) { interactor.validateRegistrationFields(any()) } coVerify(exactly = 0) { interactor.register(any()) } @@ -245,6 +248,7 @@ class SignUpViewModelTest { advanceUntilIdle() verify(exactly = 0) { analytics.setUserIdForSession(any()) } verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } coVerify(exactly = 1) { interactor.validateRegistrationFields(any()) } coVerify(exactly = 0) { interactor.register(any()) } coVerify(exactly = 0) { interactor.login(any(), any()) } @@ -298,6 +302,7 @@ class SignUpViewModelTest { coVerify(exactly = 1) { interactor.register(any()) } coVerify(exactly = 1) { interactor.login(any(), any()) } verify(exactly = 2) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } verify(exactly = 1) { appNotifier.notifier } assertFalse(viewModel.uiState.value.validationError) diff --git a/core/build.gradle b/core/build.gradle index 2360efd4d..c18b5ad0c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -114,6 +114,10 @@ dependencies { api "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" api "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + // Fullstory + api 'com.fullstory:instrumentation-full:1.47.0@aar' + api 'com.fullstory:compose:1.47.0@aar' + // Room api "androidx.room:room-runtime:$room_version" api "androidx.room:room-ktx:$room_version" diff --git a/core/src/main/java/org/openedx/core/config/Config.kt b/core/src/main/java/org/openedx/core/config/Config.kt index 57f91ef88..528ff4cc8 100644 --- a/core/src/main/java/org/openedx/core/config/Config.kt +++ b/core/src/main/java/org/openedx/core/config/Config.kt @@ -65,6 +65,10 @@ class Config(context: Context) { return getObjectOrNewInstance(SEGMENT_IO, SegmentConfig::class.java) } + fun getFullstoryConfig(): FullstoryConfig { + return getObjectOrNewInstance(FULLSTORY, FullstoryConfig::class.java) + } + fun getBrazeConfig(): BrazeConfig { return getObjectOrNewInstance(BRAZE, BrazeConfig::class.java) } @@ -158,6 +162,7 @@ class Config(context: Context) { private const val SOCIAL_AUTH_ENABLED = "SOCIAL_AUTH_ENABLED" private const val FIREBASE = "FIREBASE" private const val SEGMENT_IO = "SEGMENT_IO" + private const val FULLSTORY = "FULLSTORY" private const val BRAZE = "BRAZE" private const val FACEBOOK = "FACEBOOK" private const val GOOGLE = "GOOGLE" diff --git a/core/src/main/java/org/openedx/core/config/FullstoryConfig.kt b/core/src/main/java/org/openedx/core/config/FullstoryConfig.kt new file mode 100644 index 000000000..00bc00e81 --- /dev/null +++ b/core/src/main/java/org/openedx/core/config/FullstoryConfig.kt @@ -0,0 +1,11 @@ +package org.openedx.core.config + +import com.google.gson.annotations.SerializedName + +data class FullstoryConfig( + @SerializedName("ENABLED") + val isEnabled: Boolean = false, + + @SerializedName("ORG_ID") + private val orgId: String = "" +) diff --git a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt index 6c57df741..26806897f 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt @@ -1253,9 +1253,9 @@ fun RoundTabsBar( .then(border) .clickable { scope.launch { + onTabClicked(index) pagerState.scrollToPage(index) rowState.animateScrollToItem(index) - onTabClicked(index) } } .padding(horizontal = 16.dp), diff --git a/course/src/main/java/org/openedx/course/presentation/CourseAnalytics.kt b/course/src/main/java/org/openedx/course/presentation/CourseAnalytics.kt index 8151226c0..0dbe660e5 100644 --- a/course/src/main/java/org/openedx/course/presentation/CourseAnalytics.kt +++ b/course/src/main/java/org/openedx/course/presentation/CourseAnalytics.kt @@ -38,6 +38,7 @@ interface CourseAnalytics { fun finishVerticalBackClickedEvent(courseId: String, courseName: String) fun logEvent(event: String, params: Map) + fun logScreenEvent(screenName: String, params: Map) } enum class CourseAnalyticsEvent(val eventName: String, val biValue: String) { 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 97045561e..60813d29a 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 @@ -420,8 +420,8 @@ class CourseContainerViewModel( } private fun logCourseContainerEvent(event: CourseAnalyticsEvent) { - courseAnalytics.logEvent( - event = event.eventName, + courseAnalytics.logScreenEvent( + screenName = event.eventName, params = buildMap { put(CourseAnalyticsKey.NAME.key, event.biValue) put(CourseAnalyticsKey.COURSE_ID.key, courseId) diff --git a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt index 7381402b2..76197b93c 100644 --- a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesScreen.kt @@ -41,6 +41,7 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.KeyboardArrowUp import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -212,6 +213,17 @@ private fun CourseDatesUI( HandleUIMessage(uiMessage = uiMessage, scaffoldState = scaffoldState) + val isPLSBannerAvailable = (uiState as? DatesUIState.Dates) + ?.courseDatesResult + ?.courseBanner + ?.isBannerAvailableForUserType(isSelfPaced) + + LaunchedEffect(key1 = isPLSBannerAvailable) { + if (isPLSBannerAvailable == true) { + onPLSBannerViewed() + } + } + Box( modifier = Modifier .fillMaxSize() @@ -249,7 +261,6 @@ private fun CourseDatesUI( if (courseBanner.isBannerAvailableForUserType(isSelfPaced)) { item { - onPLSBannerViewed() if (windowSize.isTablet) { CourseDatesBannerTablet( modifier = Modifier.padding(top = 16.dp), diff --git a/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsViewModel.kt b/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsViewModel.kt index 66ba39293..92aaa139d 100644 --- a/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/handouts/HandoutsViewModel.kt @@ -98,8 +98,8 @@ class HandoutsViewModel( } fun logEvent(event: CourseAnalyticsEvent) { - courseAnalytics.logEvent( - event = event.eventName, + courseAnalytics.logScreenEvent( + screenName = event.eventName, params = buildMap { put(CourseAnalyticsKey.NAME.key, event.biValue) put(CourseAnalyticsKey.COURSE_ID.key, courseId) diff --git a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt index 938d850d2..f049e3751 100644 --- a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt @@ -171,12 +171,12 @@ class CourseContainerViewModelTest { ) every { networkConnection.isOnline() } returns true coEvery { interactor.getCourseStructure(any(), any()) } throws UnknownHostException() - every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit + every { analytics.logScreenEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() coVerify(exactly = 1) { interactor.getCourseStructure(any(), any()) } - verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } + verify(exactly = 1) { analytics.logScreenEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } val message = viewModel.errorMessage.value assertEquals(noInternet, message) @@ -205,12 +205,12 @@ class CourseContainerViewModelTest { ) every { networkConnection.isOnline() } returns true coEvery { interactor.getCourseStructure(any(), any()) } throws Exception() - every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit + every { analytics.logScreenEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() coVerify(exactly = 1) { interactor.getCourseStructure(any(), any()) } - verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } + verify(exactly = 1) { analytics.logScreenEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } val message = viewModel.errorMessage.value assertEquals(somethingWrong, message) @@ -239,12 +239,12 @@ class CourseContainerViewModelTest { ) every { networkConnection.isOnline() } returns true coEvery { interactor.getCourseStructure(any(), any()) } returns courseStructure - every { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit + every { analytics.logScreenEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } returns Unit viewModel.preloadCourseStructure() advanceUntilIdle() coVerify(exactly = 1) { interactor.getCourseStructure(any(), any()) } - verify(exactly = 1) { analytics.logEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } + verify(exactly = 1) { analytics.logScreenEvent(CourseAnalyticsEvent.DASHBOARD.eventName, any()) } assert(viewModel.errorMessage.value == null) assert(!viewModel.refreshing.value) @@ -272,7 +272,7 @@ class CourseContainerViewModelTest { ) every { networkConnection.isOnline() } returns false coEvery { interactor.getCourseStructure(any(), any()) } returns courseStructure - every { analytics.logEvent(any(), any()) } returns Unit + every { analytics.logScreenEvent(any(), any()) } returns Unit coEvery { courseApi.getCourseStructure(any(), any(), any(), any()) } returns courseStructureModel @@ -280,7 +280,7 @@ class CourseContainerViewModelTest { advanceUntilIdle() coVerify(exactly = 0) { courseApi.getCourseStructure(any(), any(), any(), any()) } - verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } assert(viewModel.errorMessage.value == null) assert(!viewModel.refreshing.value) diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardAnalytics.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardAnalytics.kt index 6a69e7a65..cf7097a64 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardAnalytics.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardAnalytics.kt @@ -1,5 +1,21 @@ package org.openedx.dashboard.presentation interface DashboardAnalytics { + fun logScreenEvent(screenName: String, params: Map) fun dashboardCourseClickedEvent(courseId: String, courseName: String) } + +enum class DashboardAnalyticsEvent(val eventName: String, val biValue: String) { + MY_COURSES( + "MainDashboard:My Courses", + "edx.bi.app.main_dashboard.my_course" + ), + MY_PROGRAMS( + "MainDashboard:My Programs", + "edx.bi.app.main_dashboard.my_program" + ), +} + +enum class DashboardAnalyticsKey(val key: String) { + NAME("name"), +} diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt index 1fc574f41..b1f4bbbb7 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt @@ -93,6 +93,17 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { } binding.viewPager.adapter = adapter binding.viewPager.setUserInputEnabled(false) + + binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + if (LearnType.COURSES.ordinal == position) { + viewModel.logMyCoursesTabClickedEvent() + } else { + viewModel.logMyProgramsTabClickedEvent() + } + } + }) } companion object { diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt index 62ee774cb..9a2d17f1e 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt @@ -4,11 +4,15 @@ import androidx.fragment.app.FragmentManager import org.openedx.DashboardNavigator import org.openedx.core.BaseViewModel import org.openedx.core.config.Config +import org.openedx.dashboard.presentation.DashboardAnalytics +import org.openedx.dashboard.presentation.DashboardAnalyticsEvent +import org.openedx.dashboard.presentation.DashboardAnalyticsKey import org.openedx.dashboard.presentation.DashboardRouter class LearnViewModel( private val config: Config, private val dashboardRouter: DashboardRouter, + private val analytics: DashboardAnalytics, ) : BaseViewModel() { private val dashboardType get() = config.getDashboardConfig().getType() @@ -21,4 +25,21 @@ class LearnViewModel( val getDashboardFragment get() = DashboardNavigator(dashboardType).getDashboardFragment() val getProgramFragment get() = dashboardRouter.getProgramFragment() + + fun logMyCoursesTabClickedEvent() { + logScreenEvent(DashboardAnalyticsEvent.MY_COURSES) + } + + fun logMyProgramsTabClickedEvent() { + logScreenEvent(DashboardAnalyticsEvent.MY_PROGRAMS) + } + + private fun logScreenEvent(event: DashboardAnalyticsEvent) { + analytics.logScreenEvent( + screenName = event.eventName, + params = buildMap { + put(DashboardAnalyticsKey.NAME.key, event.biValue) + } + ) + } } diff --git a/default_config/dev/config.yaml b/default_config/dev/config.yaml index eee22e36d..a97d7c351 100644 --- a/default_config/dev/config.yaml +++ b/default_config/dev/config.yaml @@ -69,6 +69,10 @@ BRANCH: HOST: '' ALTERNATE_HOST: '' +FULLSTORY: + ENABLED: false + ORG_ID: '' + #Platform names PLATFORM_NAME: "OpenEdX" PLATFORM_FULL_NAME: "OpenEdX" diff --git a/default_config/prod/config.yaml b/default_config/prod/config.yaml index eee22e36d..a97d7c351 100644 --- a/default_config/prod/config.yaml +++ b/default_config/prod/config.yaml @@ -69,6 +69,10 @@ BRANCH: HOST: '' ALTERNATE_HOST: '' +FULLSTORY: + ENABLED: false + ORG_ID: '' + #Platform names PLATFORM_NAME: "OpenEdX" PLATFORM_FULL_NAME: "OpenEdX" diff --git a/default_config/stage/config.yaml b/default_config/stage/config.yaml index eee22e36d..a97d7c351 100644 --- a/default_config/stage/config.yaml +++ b/default_config/stage/config.yaml @@ -69,6 +69,10 @@ BRANCH: HOST: '' ALTERNATE_HOST: '' +FULLSTORY: + ENABLED: false + ORG_ID: '' + #Platform names PLATFORM_NAME: "OpenEdX" PLATFORM_FULL_NAME: "OpenEdX" diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/DiscoveryAnalytics.kt b/discovery/src/main/java/org/openedx/discovery/presentation/DiscoveryAnalytics.kt index 4540a0d7f..23994a3fb 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/DiscoveryAnalytics.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/DiscoveryAnalytics.kt @@ -5,6 +5,7 @@ interface DiscoveryAnalytics { fun discoveryCourseSearchEvent(label: String, coursesCount: Int) fun discoveryCourseClickedEvent(courseId: String, courseName: String) fun logEvent(event: String, params: Map) + fun logScreenEvent(screenName: String, params: Map) } enum class DiscoveryAnalyticsEvent(val eventName: String, val biValue: String) { diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/WebViewDiscoveryViewModel.kt b/discovery/src/main/java/org/openedx/discovery/presentation/WebViewDiscoveryViewModel.kt index f86eef2b8..e786a3970 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/WebViewDiscoveryViewModel.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/WebViewDiscoveryViewModel.kt @@ -77,7 +77,7 @@ class WebViewDiscoveryViewModel( event: DiscoveryAnalyticsEvent, courseId: String, ) { - analytics.logEvent( + analytics.logScreenEvent( event.eventName, buildMap { put(DiscoveryAnalyticsKey.NAME.key, event.biValue) diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt b/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt index 6d41ac4b1..487027e8f 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/info/CourseInfoViewModel.kt @@ -146,11 +146,11 @@ class CourseInfoViewModel( } fun courseInfoClickedEvent(courseId: String) { - logEvent(DiscoveryAnalyticsEvent.COURSE_INFO, courseId) + logScreenEvent(DiscoveryAnalyticsEvent.COURSE_INFO, courseId) } fun programInfoClickedEvent(courseId: String) { - logEvent(DiscoveryAnalyticsEvent.PROGRAM_INFO, courseId) + logScreenEvent(DiscoveryAnalyticsEvent.PROGRAM_INFO, courseId) } fun courseEnrollClickedEvent(courseId: String) { @@ -165,15 +165,26 @@ class CourseInfoViewModel( event: DiscoveryAnalyticsEvent, courseId: String, ) { - analytics.logEvent( - event.eventName, - buildMap { - put(DiscoveryAnalyticsKey.NAME.key, event.biValue) - put(DiscoveryAnalyticsKey.COURSE_ID.key, courseId) - put(DiscoveryAnalyticsKey.CATEGORY.key, CoreAnalyticsKey.DISCOVERY.key) - put(DiscoveryAnalyticsKey.CONVERSION.key, courseId) - } - ) + analytics.logEvent(event.eventName, buildEventDataMap(event, courseId)) + } + + private fun logScreenEvent( + event: DiscoveryAnalyticsEvent, + courseId: String, + ) { + analytics.logScreenEvent(event.eventName, buildEventDataMap(event, courseId)) + } + + private fun buildEventDataMap( + event: DiscoveryAnalyticsEvent, + courseId: String, + ): Map { + return buildMap { + put(DiscoveryAnalyticsKey.NAME.key, event.biValue) + put(DiscoveryAnalyticsKey.COURSE_ID.key, courseId) + put(DiscoveryAnalyticsKey.CATEGORY.key, CoreAnalyticsKey.DISCOVERY.key) + put(DiscoveryAnalyticsKey.CONVERSION.key, courseId) + } } companion object { diff --git a/profile/src/main/java/org/openedx/profile/presentation/ProfileAnalytics.kt b/profile/src/main/java/org/openedx/profile/presentation/ProfileAnalytics.kt index 2422ba505..684fc309e 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/ProfileAnalytics.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/ProfileAnalytics.kt @@ -2,9 +2,14 @@ package org.openedx.profile.presentation interface ProfileAnalytics { fun logEvent(event: String, params: Map) + fun logScreenEvent(screenName: String, params: Map) } enum class ProfileAnalyticsEvent(val eventName: String, val biValue: String) { + EDIT_PROFILE( + "Profile:Edit Profile", + "edx.bi.app.profile.edit" + ), EDIT_CLICKED( "Profile:Edit Clicked", "edx.bi.app.profile.edit.clicked" diff --git a/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileViewModel.kt b/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileViewModel.kt index 64cf9789f..211ce2794 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileViewModel.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/edit/EditProfileViewModel.kt @@ -67,6 +67,9 @@ class EditProfileViewModel( val showLeaveDialog: LiveData get() = _showLeaveDialog + init { + logProfileScreenEvent(ProfileAnalyticsEvent.EDIT_PROFILE) + } fun updateAccount(fields: Map) { _uiState.value = EditProfileUIState(account, true, isLimitedProfile) @@ -156,4 +159,18 @@ class EditProfileViewModel( } ) } + + private fun logProfileScreenEvent( + event: ProfileAnalyticsEvent, + params: Map = emptyMap(), + ) { + analytics.logScreenEvent( + screenName = event.eventName, + params = buildMap { + put(ProfileAnalyticsKey.NAME.key, event.biValue) + put(ProfileAnalyticsKey.CATEGORY.key, ProfileAnalyticsKey.PROFILE.key) + putAll(params) + } + ) + } } diff --git a/profile/src/test/java/org/openedx/profile/presentation/edit/EditProfileViewModelTest.kt b/profile/src/test/java/org/openedx/profile/presentation/edit/EditProfileViewModelTest.kt index bfe6bb0b3..a9b5b0c31 100644 --- a/profile/src/test/java/org/openedx/profile/presentation/edit/EditProfileViewModelTest.kt +++ b/profile/src/test/java/org/openedx/profile/presentation/edit/EditProfileViewModelTest.kt @@ -64,6 +64,7 @@ class EditProfileViewModelTest { Dispatchers.setMain(dispatcher) every { resourceManager.getString(R.string.core_error_no_connection) } returns noInternet every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong + every { analytics.logScreenEvent(any(), any()) } returns Unit } @After @@ -172,6 +173,7 @@ class EditProfileViewModelTest { advanceUntilIdle() verify(exactly = 1) { analytics.logEvent(any(), any()) } + verify(exactly = 1) { analytics.logScreenEvent(any(), any()) } coVerify(exactly = 1) { interactor.updateAccount(any()) } coVerify(exactly = 1) { interactor.setProfileImage(any(), any()) } diff --git a/settings.gradle b/settings.gradle index 66cb04c11..8f539415d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,6 +3,7 @@ pluginManagement { gradlePluginPortal() google() mavenCentral() + maven { url "https://maven.fullstory.com" } } buildscript { repositories { @@ -10,9 +11,11 @@ pluginManagement { maven { url = uri("https://storage.googleapis.com/r8-releases/raw") } + maven { url "https://maven.fullstory.com" } } dependencies { classpath("com.android.tools:r8:8.2.26") + classpath 'com.fullstory:gradle-plugin-local:1.47.0' } } } @@ -21,6 +24,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url "https://maven.fullstory.com" } maven { url "http://appboy.github.io/appboy-android-sdk/sdk" allowInsecureProtocol = true From 29d307dfc85773a9c3b75955c0bf11b24e3b4760 Mon Sep 17 00:00:00 2001 From: Farhan Arshad Date: Fri, 15 Mar 2024 11:12:14 +0500 Subject: [PATCH 29/38] chore: add colors and resource for edx theme/branding --- .../res/drawable/ic_launcher_foreground.xml | 24 +++ .../edx/res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/edx/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 5181 bytes app/src/edx/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 3516 bytes app/src/edx/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 7149 bytes app/src/edx/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 11241 bytes .../edx/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 15693 bytes .../edx/org/openedx/core/ui/theme/Colors.kt | 145 ++++++++++++++++++ .../org/openedx/core/ui/theme/LocalShapes.kt | 25 +++ .../ui/theme/compose/LogistrationLogoView.kt | 31 ++++ .../core/ui/theme/compose/SignInLogoView.kt | 39 +++++ .../edx/res/drawable-night/core_ic_logo.xml | 15 ++ .../res/drawable-night/core_top_header.png | Bin 0 -> 5798 bytes core/src/edx/res/drawable/core_ic_logo.xml | 18 +++ .../edx/res/drawable/core_ic_logo_white.xml | 15 ++ core/src/edx/res/drawable/core_top_header.png | Bin 0 -> 5798 bytes core/src/edx/res/font/black.ttf | Bin 0 -> 316372 bytes core/src/edx/res/font/bold.ttf | Bin 0 -> 316100 bytes core/src/edx/res/font/extra_light.ttf | Bin 0 -> 311232 bytes core/src/edx/res/font/light.ttf | Bin 0 -> 310832 bytes core/src/edx/res/font/medium.ttf | Bin 0 -> 314712 bytes core/src/edx/res/font/regular.ttf | Bin 0 -> 680112 bytes core/src/edx/res/font/semi_bold.ttf | Bin 0 -> 709668 bytes core/src/edx/res/font/thin.ttf | Bin 0 -> 310984 bytes core/src/edx/res/values-night/colors.xml | 7 + core/src/edx/res/values/colors.xml | 7 + 27 files changed, 336 insertions(+) create mode 100644 app/src/edx/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/edx/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/edx/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/edx/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/edx/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/edx/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/edx/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/edx/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 core/src/edx/org/openedx/core/ui/theme/Colors.kt create mode 100644 core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt create mode 100644 core/src/edx/org/openedx/core/ui/theme/compose/LogistrationLogoView.kt create mode 100644 core/src/edx/org/openedx/core/ui/theme/compose/SignInLogoView.kt create mode 100644 core/src/edx/res/drawable-night/core_ic_logo.xml create mode 100644 core/src/edx/res/drawable-night/core_top_header.png create mode 100644 core/src/edx/res/drawable/core_ic_logo.xml create mode 100644 core/src/edx/res/drawable/core_ic_logo_white.xml create mode 100644 core/src/edx/res/drawable/core_top_header.png create mode 100644 core/src/edx/res/font/black.ttf create mode 100644 core/src/edx/res/font/bold.ttf create mode 100644 core/src/edx/res/font/extra_light.ttf create mode 100644 core/src/edx/res/font/light.ttf create mode 100644 core/src/edx/res/font/medium.ttf create mode 100644 core/src/edx/res/font/regular.ttf create mode 100644 core/src/edx/res/font/semi_bold.ttf create mode 100644 core/src/edx/res/font/thin.ttf create mode 100644 core/src/edx/res/values-night/colors.xml create mode 100644 core/src/edx/res/values/colors.xml diff --git a/app/src/edx/res/drawable/ic_launcher_foreground.xml b/app/src/edx/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..f542143cc --- /dev/null +++ b/app/src/edx/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/edx/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/edx/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..6b78462d6 --- /dev/null +++ b/app/src/edx/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/edx/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/edx/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..6b78462d6 --- /dev/null +++ b/app/src/edx/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/edx/res/mipmap-hdpi/ic_launcher.png b/app/src/edx/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..3bcadcfdffb6e1aed8e93bb9eecae1b128aaaff3 GIT binary patch literal 5181 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 I%{Jt}02)@;`~Uy| literal 0 HcmV?d00001 diff --git a/app/src/edx/res/mipmap-mdpi/ic_launcher.png b/app/src/edx/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4184318fde90f2a61f5f26ed95b2debcd5664d80 GIT binary patch literal 3516 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 literal 0 HcmV?d00001 diff --git a/app/src/edx/res/mipmap-xhdpi/ic_launcher.png b/app/src/edx/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..683b4aa56eec5cd95a17b4240161a4de64d8c572 GIT binary patch literal 7149 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 literal 0 HcmV?d00001 diff --git a/app/src/edx/res/mipmap-xxhdpi/ic_launcher.png b/app/src/edx/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f6467b999a4995580db807a40889aaea7a4518be GIT binary patch literal 11241 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 literal 0 HcmV?d00001 diff --git a/app/src/edx/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/edx/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c82b65553f4090a6d294e9513e7430a74b8d3bf9 GIT binary patch literal 15693 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 +val light_certificate_foreground = Color.White +val light_bottom_sheet_toggle = Color(0xFF03C7E8) // Accent A Isotope Blue + +val light_rate_stars = Color(0xFFF0CC00) // Accent B Oxide Yellow +val light_inactive_button_background = Color(0xFFCCD4E0) +val light_access_green = Color(0xFF23BCA0) +val light_dates_section_bar_past_due = Color(0xFFF0CC00) +val light_dates_section_bar_today = light_info +val light_dates_section_bar_this_week = light_text_primary_variant +val light_dates_section_bar_next_week = light_text_field_border +val light_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val light_auth_google_button_background = Color.White +val light_auth_facebook_button_background = Color(0xFF0866FF) +val light_auth_microsoft_button_background = Color(0xFF2E2E2E) +val light_component_horizontal_progress_completed_and_selected = light_primary +val light_component_horizontal_progress_completed = Color(0xFF8F8F8F) +val light_component_horizontal_progress_selected = light_primary +val light_component_horizontal_progress_default = Color(0xFF8F8F8F) + + +// Dark theme colors scheme +val dark_primary = Color(0xFFFBFAF9) // Light 200 +val dark_primary_variant = Color(0xFFF2F0EF) // Light 300 +val dark_secondary = Color(0xFFD23228) // Brand 500 +val dark_secondary_variant = Color(0xFFD23228) // Brand 500 +val dark_background = Color(0xFF00262b) // Primary 500 | Dark 500 +val dark_surface = Color(0xFF002121) // Primary 700 | Dark 700 +val dark_error = Color(0xFFAB0D02) // Danger 500 +val dark_warning = Color(0xFFF0CC00) // Accent B Oxide Yellow +val dark_info = Color(0xFF03C7E8) // Accent A Isotope Blue +val dark_info_variant = Color(0xFF00688D) // Info 500 + +val dark_onPrimary = Color(0xFF002121) // Primary 700 | Dark 700 +val dark_onSecondary = Color.White +val dark_onBackground = Color.White +val dark_onSurface = Color.White +val dark_onError = Color.White +val dark_onWarning = Color.White +val dark_onInfo = Color.White + + +val dark_text_primary = Color.White +val dark_text_primary_variant = Color(0xFFF2F0EF) // Light 300 +val dark_text_primary_light = Color(0xFF707070) // Gray 500 +val dark_text_hyper_link = Color(0xFF00688D) // Info 500 + +val dark_text_secondary = Color.White +val dark_text_dark = Color(0xFFF2F0EF) // Light 300 +val dark_text_warning = Color(0xFFF2F0EF) // Light 300 + +val dark_text_accent = Color(0xFF03C7E8) // Accent A Isotope Blue +val dark_text_field_background = Color.White +val dark_text_field_background_variant = Color.White +val dark_text_field_border = Color(0xFF707070) // Gray 500 +val dark_text_field_text = Color.White +val dark_text_field_hint = Color(0xFF707070) // Gray 500 + +val dark_primary_button_background = Color(0xFF00262B) // Primary 500 | Dark 500 | Elm +val dark_primary_button_text = Color.White +val dark_primary_button_border = Color(0xFFD7D3D1) // Light 700 +val dark_primary_button_bordered_text = Color(0xFF00262B) // Primary 500 | Dark 500 | Elm + +val dark_secondary_button_background = Color(0xFFD23228) // Brand 500 +val dark_secondary_button_text = Color.White +val dark_secondary_button_border = Color(0xFFD7D3D1) // Light 700 +val dark_secondary_button_bordered_background = Color.White +val dark_secondary_button_bordered_text = Color(0xFFD23228) // Brand 500 + +val dark_card_view_background = Color(0xFF003839) +val dark_card_view_border = Color(0xFF4E5A70) +val dark_divider = Color(0xFF0E3639) // Dark 400 + +val dark_certificate_foreground = Color(0xD92EB865) +val dark_bottom_sheet_toggle = Color(0xFF03C7E8) // Accent A Isotope Blue +val dark_rate_stars = Color(0xFFF0CC00) // Accent B Oxide Yellow +val dark_inactive_button_background = Color(0xFFCCD4E0) +val dark_access_green = Color(0xFF23BCA0) +val dark_dates_section_bar_past_due = Color(0xFFF0CC00) // Accent B Oxide Yellow +val dark_dates_section_bar_today = Color(0xFF03C7E8) // Accent A Isotope Blue +val dark_dates_section_bar_this_week = Color(0xFFF2F0EF) // Light 300 +val dark_dates_section_bar_next_week = Color(0xFF707070) // Gray 500 +val dark_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val dark_auth_google_button_background = Color.White +val dark_auth_facebook_button_background = Color(0xFF0866FF) +val dark_auth_microsoft_button_background = Color(0xFF2E2E2E) +val dark_component_horizontal_progress_completed_and_selected = Color.White +val dark_component_horizontal_progress_completed = Color(0xFF8F8F8F) +val dark_component_horizontal_progress_selected = Color.White +val dark_component_horizontal_progress_default = Color(0xFF8F8F8F) diff --git a/core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt b/core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt new file mode 100644 index 000000000..19da9b1c9 --- /dev/null +++ b/core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt @@ -0,0 +1,25 @@ +package org.openedx.core.ui.theme + +import androidx.compose.foundation.shape.CornerSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.unit.dp + +internal val LocalShapes = staticCompositionLocalOf { + AppShapes( + material = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(8.dp), + large = RoundedCornerShape(0.dp) + ), + buttonShape = RoundedCornerShape(0.dp), + navigationButtonShape = RoundedCornerShape(0.dp), + textFieldShape = RoundedCornerShape(CornerSize(0.dp)), + screenBackgroundShape = RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp), + cardShape = RoundedCornerShape(0.dp), + screenBackgroundShapeFull = RoundedCornerShape(24.dp), + courseImageShape = RoundedCornerShape(0.dp), + dialogShape = RoundedCornerShape(24.dp) + ) +} diff --git a/core/src/edx/org/openedx/core/ui/theme/compose/LogistrationLogoView.kt b/core/src/edx/org/openedx/core/ui/theme/compose/LogistrationLogoView.kt new file mode 100644 index 000000000..c9f1f77e8 --- /dev/null +++ b/core/src/edx/org/openedx/core/ui/theme/compose/LogistrationLogoView.kt @@ -0,0 +1,31 @@ +package org.openedx.core.ui.theme.compose + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.openedx.core.R +import org.openedx.core.ui.theme.OpenEdXTheme + +@Composable +fun LogistrationLogoView() { + Image( + modifier = Modifier + .padding(top = 64.dp, bottom = 20.dp) + .wrapContentWidth(), + painter = painterResource(id = R.drawable.core_ic_logo), + contentDescription = null, + ) +} + +@Preview(widthDp = 375) +@Composable +fun LogistrationLogoViewPreview() { + OpenEdXTheme { + LogistrationLogoView() + } +} diff --git a/core/src/edx/org/openedx/core/ui/theme/compose/SignInLogoView.kt b/core/src/edx/org/openedx/core/ui/theme/compose/SignInLogoView.kt new file mode 100644 index 000000000..80e3f7967 --- /dev/null +++ b/core/src/edx/org/openedx/core/ui/theme/compose/SignInLogoView.kt @@ -0,0 +1,39 @@ +package org.openedx.core.ui.theme.compose + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.openedx.core.R +import org.openedx.core.ui.theme.OpenEdXTheme + +@Composable +fun SignInLogoView() { + Box( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(0.2f), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(id = R.drawable.core_ic_logo_white), + contentDescription = null, + modifier = Modifier.padding(top = 20.dp) + ) + } +} + +@Preview(widthDp = 375, heightDp = 400) +@Composable +fun SignInLogoViewPreview() { + OpenEdXTheme { + SignInLogoView() + } +} diff --git a/core/src/edx/res/drawable-night/core_ic_logo.xml b/core/src/edx/res/drawable-night/core_ic_logo.xml new file mode 100644 index 000000000..8e08c5334 --- /dev/null +++ b/core/src/edx/res/drawable-night/core_ic_logo.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/core/src/edx/res/drawable-night/core_top_header.png b/core/src/edx/res/drawable-night/core_top_header.png new file mode 100644 index 0000000000000000000000000000000000000000..8e34e2d73c23a3aaed6a970601e0fe2879a1c06d GIT binary patch literal 5798 zcmeHK2UinY*Pal1FM^07p(sU2=+X(&ktTwK08#@YodgJCqy!P9N>h-gfG8kMs`Mg= zQlu!L6p<<_VCW_A2KCs@eSIdQxFMJdDs1lPUU#*z=te$NOKgv{G|m;#e5V2#%`r*nb;XCZzb0M)dqC;l z(J#QizMLixQ*#5nj zNDF<6pb-9)7s(yhgt~4!i>%o=uZ+^-^ee^rp)B^a?Q`3qVbl?3ynZixZZllmiWcj( z)ui8!I3+Q#*TWk-MTaNO?jUZY$q8vq*(4+?O53=h!-KgWG*b~IKb@OdZ$Z|au-Ny4 zA{1?2M)M3z&BrqFq|wFkFbicVzH2+$(J6vai6HDb%s6=87E;ukin~vEhR>@PZim)x zm)$PIo;zt3?}Jk^NIJ?c*vAIzo(a?HT5T~8_G%^r1v3hi=7m0iuu;F?;oA9_TrWuN z70j6nRw*?XSLbI%DWAheQ{4P$6tM;I$EG(G-DM*19{Ao%=J}?UR&>@zmXA*9rW{pR zh#OYyP7Euf_Ibbv!oQ`BVRW;)=PBzpupiXNR5p3+v|}rKw4)H8wfoCNP91tkI5R#% zwnk+MA2>C&vOslTs<&A=eD3>r)=JVFHLQM(+JeAXDxVPRLDH<;8=7_ekxCt68Ar{j zAcahu2h@&LgTQ2eBA-HBmy??l$R`g*|1iH&E1Rh)_u8J&g>N6Q=#;A{uMGOZ$Z zMd*vR!Y`3-z6_dCcV-hQe8~?Y&SISNlDmD2e82kc@h!ieKB_a>A1q@gtuCt5_cBLn z>S&0OGhHoX&O&c&FBH&ef)R#??_U}92lu-Wd&RcEz;YrUkJoNOKM(|sEHm;P@K4IS zQtn}dz+O|-=6t<((KT!EU{4yEt=!Kbep||-sq5(>$5+U1K$ycqb(pCVnjP=qD6Qu0 z#ksr5R@EegD9$t^jX|;@Pi+N9z>L9^Ui9gd^UbI?j2^*(Uh5eA(QKZ2a25+WFRy7> z_yTW71cm)AIez+fDjJQ}JDdVEx@rR~ynJd-ymavgPxZ~0V|!vivXY6&W{bg$x)R12;Yj1-ib zo-WWaO?mRwSU%53dzK+tuQGS%LgJHvA=D7p;;}{bMJltj0=$T2a=wCjrAg)G^@7Fo zGUaJExh}ewBOf4B->X%gxr$qK^gZvJqM(h7y_UDbvTnHu=8|R*jM0fX5tGMNCk?&2 zb|pbtOa?3ykVYp{eKoWH>q9$fDXyrFJh5!|oQynQSC-16iV7bpCK}Rj<{&-uxGb#}1(#-Q0t6bIDN|bd#u@*Y4(N zU*v{0i+hS~#>d9nJ$yYHmgbg(m&}%`Ig!yq9VQ(VOrf`$I<4XyPVy*^E3GOqVfSZI z%gM8quM3@v-Xiu#+#Txb4I1PpEbA3<3o61Y_i+k1gX{8*ZyV!?-Fw&@ABdR}?)Or= z$Gh+D$L`x7wCyijWEPDUT?8TEUT|HwWww*;bz9AkZIHq2we0uV`?kX$Q(N-SQS;jI zo>BKGV;HsaW2jRdQpWgQIe$+N;fBy0nfChN<&7Pb!&oiUyq#XsMrcs;bMdJODEj!$ z;DrhwyIj!DiR{17pWJWckZ$kvB0Vneg<<44`!2Ls)gxf60s953dmSB$Y;6xq3)_qY zMHaFucE+7l4cwa*APT6NI7kZ1^9BSGn!}oDTm>;km<)u{_c?(=U5Z4g;k&GKF{`du}dTwBT ziQ#h3N{`U%1-4Rh_E7Uw-qib&lg^q>-(GTc8+K3J&q+#5Kx;e}?q;phmq|m4SE@S- zig5TEuBKP{A)Dm%>y?joWh8yLmroHiV|nUbf{j2N0Y^Bqs;X~v??x#+2ab57(B{{X zaIB9OPaAYUvTvr>EfXc_x?iOIEcID+x7u88uS=$@tpC*5Qb5b9UvGYQU)n+79f$sc zht+hfN2SH2t>irIhG8vDLmY)1QBj^^1Z0JaL?fcK#=Yy_sV{f0pP5Rw67dxkJ3}l_ zs#_ZFdXP^b}gxA@>wJ$u}o*__&Z%<6NU&%8*C+0DY|m*Om~o5C9(Ire<0y!h_2 zC|dYKMQpiYdGRx)`g-q%?H%?nO{R{fV~^KL#w=0BmAQ*V%8Bs8<3!na?vi7s&p!`3 zwak6646PnAx4d-M{gg+~|kcbL1CJ44aIuWG1fc<8I-NM$|8 z)8wIzrOcW-oKbUThr;f2u|VIAlqK-4z;5QU(P+>rd?aKJAC33DCCX^V{fHa-M0?SB zX!ES2G)DHcjNb_w<$Yo^rsG4p!n=H&Pp|Dc)&%hB0F%ieP&rW+zG|GIxH19s~EmLvS|MGZG z)9&^}{chOqDW)NwBxPwVf_STkCs1)*Ax@PRJG3LW@x1}+F&rgWYt)E=UDv}QH@deh z4C2szWfR#G8}n?L{!PpcTVv*X`5jqiu%|XBcU~`-yxady94~1vp|pYFayFehE$>$M zfG>cVCTHt+_ZnyL6Sp#Wj`8#b>Fuq3U0s9a!e(vU8)b2HyM969&R)jtENI6jGETQE zNG_nnAAlQ>1ygQ1C(#gyS>4RrnP%b5L9GPkhuveqWBkE#KW=4tjsw`OYWa3_$oxJv z{0Mun98+-YF{!cejjQFjyrBp$o>KW4*Q*mQ^ zK`Ep^iWC$=*U7*D5FyFb00oE@0FxvT=>$Mr0L2d(0Q5k||CCKYLccI%0C39%ApeCy zlIFuBo-|18Uo$u%9H1iIv64nuHrXF&kbgG#4;g4B*#NbR>bkn5`J#gl3gv;m;)xMa zNqb9D(0J)spaFp6)ZqZ>nh2}_0NJpMDFTBq&{uHqbcfnGdfKC)Sa+{OKY$Wefh4-4 zFm@2EyPF4E0jtdS1ED~Y57jU}$PWm{RhbWAU<^_B^g%&nq2f?+J{4LB1ft~Q=%iqx zq4kSSx>M%6g28wxz+nFV{!o7@sHcxJOhR5>9wsgclav%AA;i!D9vC~UmQd0jX}On4r*}ZoY?0Xy)O9QIS-F{ge9dEQ`Nr zDiVj~{UH6W{W}BkkBr~7e`gr^xRBPt?l3hKiC+ + + + + + diff --git a/core/src/edx/res/drawable/core_ic_logo_white.xml b/core/src/edx/res/drawable/core_ic_logo_white.xml new file mode 100644 index 000000000..8e08c5334 --- /dev/null +++ b/core/src/edx/res/drawable/core_ic_logo_white.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/core/src/edx/res/drawable/core_top_header.png b/core/src/edx/res/drawable/core_top_header.png new file mode 100644 index 0000000000000000000000000000000000000000..8e34e2d73c23a3aaed6a970601e0fe2879a1c06d GIT binary patch literal 5798 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 literal 0 HcmV?d00001 diff --git a/core/src/edx/res/font/bold.ttf b/core/src/edx/res/font/bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8e82c70d1081e2857ada1b73395d4f42c2e8adc9 GIT binary patch literal 316100 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�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

6=3(=QnPeuLDdti0n3-y(nd#Q;7fbjCmF@fSxxm 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

1I|svCvU|R`iQp*F3zg>=ixMX$T~z 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�dQ42l5tk(k!kqW$Z9oaaPl9Brl>h&Mw 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

-!3)&^3_);e$#d3!A`}>2A0`eCa`SL&sov0 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 literal 0 HcmV?d00001 diff --git a/core/src/edx/res/font/regular.ttf b/core/src/edx/res/font/regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3b7e686e5479bcc28931eaaf9f4e78b00899a484 GIT binary patch literal 680112 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 IF%l&Q@ps3!;nFMYOaI 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≀Nbj-$ExlKLC?kWy?B( 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�Fr)E3m?!X&m)tGhMoy~zn( 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 z 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

H+puBYg3B*w{r+F{f^TJK!;~E9 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 LRH=$jGupY!gQq$dJ%4iWri^0SAdBP!I`;33ihK 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 E3qeI@A^-pY literal 0 HcmV?d00001 diff --git a/core/src/edx/res/font/semi_bold.ttf b/core/src/edx/res/font/semi_bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..556e972f48e4504a998b03b84cded90a2d6ce157 GIT binary patch literal 709668 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 literal 0 HcmV?d00001 diff --git a/core/src/edx/res/values-night/colors.xml b/core/src/edx/res/values-night/colors.xml new file mode 100644 index 000000000..80155c620 --- /dev/null +++ b/core/src/edx/res/values-night/colors.xml @@ -0,0 +1,7 @@ + + + + #FF00262b + #FFFBFAF9 + #00262B + diff --git a/core/src/edx/res/values/colors.xml b/core/src/edx/res/values/colors.xml new file mode 100644 index 000000000..96839eb98 --- /dev/null +++ b/core/src/edx/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #FFFFFF + + #00262B + #FFFFFF + From 3720f85cc6c5b5db97c0ebfeeea2f794be9a7a74 Mon Sep 17 00:00:00 2001 From: Hamza Israr Date: Fri, 7 Jun 2024 12:33:33 +0500 Subject: [PATCH 30/38] chore: Add missing success colors for authentication screens Fixes: LEARNER-10035 --- core/src/edx/org/openedx/core/ui/theme/Colors.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/src/edx/org/openedx/core/ui/theme/Colors.kt b/core/src/edx/org/openedx/core/ui/theme/Colors.kt index 20d14e3f1..8f438fcb2 100644 --- a/core/src/edx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/edx/org/openedx/core/ui/theme/Colors.kt @@ -22,6 +22,9 @@ val light_onError = Color.White val light_onWarning = Color.White val light_onInfo = Color.White +val light_success_green = Color(0xFFF2FAF7) +val light_success_background = Color(0xFF0D7D4D) + val light_text_primary = Color(0xFF00262B) // Primary 500 | Dark 500 | Elm val light_text_primary_variant = Color(0xFF454545) // Gray 700 val light_text_primary_light = Color(0xFF707070) // Gray 500 @@ -45,7 +48,7 @@ val light_primary_button_border = Color(0xFFD7D3D1) // Light 700 val light_primary_button_bordered_text = Color(0xFF00262B) // Primary 500 | Dark 500 | Elm val light_secondary_button_background = Color(0xFFD23228) // Brand 500 -val light_secondary_button_text = Color(0xFFD23228) // Brand 500 +val light_secondary_button_text = Color(0xFFD23228) // Brand 500 val light_secondary_button_border = Color(0xFFD7D3D1) // Light 700 val light_secondary_button_bordered_background = Color.White val light_secondary_button_bordered_text = Color(0xFFD23228) // Brand 500 @@ -65,6 +68,7 @@ val light_dates_section_bar_today = light_info val light_dates_section_bar_this_week = light_text_primary_variant val light_dates_section_bar_next_week = light_text_field_border val light_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val light_auth_sso_success_background = light_success_green val light_auth_google_button_background = Color.White val light_auth_facebook_button_background = Color(0xFF0866FF) val light_auth_microsoft_button_background = Color(0xFF2E2E2E) @@ -94,6 +98,8 @@ val dark_onError = Color.White val dark_onWarning = Color.White val dark_onInfo = Color.White +val dark_success_green = Color(0xFF0A5E3A) +val dark_success_background = Color.White val dark_text_primary = Color.White val dark_text_primary_variant = Color(0xFFF2F0EF) // Light 300 @@ -136,6 +142,7 @@ val dark_dates_section_bar_today = Color(0xFF03C7E8) // Accent A Isotope Blue val dark_dates_section_bar_this_week = Color(0xFFF2F0EF) // Light 300 val dark_dates_section_bar_next_week = Color(0xFF707070) // Gray 500 val dark_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val dark_auth_sso_success_background = dark_success_green val dark_auth_google_button_background = Color.White val dark_auth_facebook_button_background = Color(0xFF0866FF) val dark_auth_microsoft_button_background = Color(0xFF2E2E2E) From 830dbe726934c3ca0caaa76861988b02d6c333a6 Mon Sep 17 00:00:00 2001 From: Farhan Arshad Date: Tue, 9 Jul 2024 21:12:24 +0500 Subject: [PATCH 31/38] fix: Add missing color for 2u/develop branch --- .../edx/org/openedx/core/ui/theme/Colors.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/src/edx/org/openedx/core/ui/theme/Colors.kt b/core/src/edx/org/openedx/core/ui/theme/Colors.kt index 8f438fcb2..22286d16b 100644 --- a/core/src/edx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/edx/org/openedx/core/ui/theme/Colors.kt @@ -77,6 +77,15 @@ val light_component_horizontal_progress_completed = Color(0xFF8F8F8F) val light_component_horizontal_progress_selected = light_primary val light_component_horizontal_progress_default = Color(0xFF8F8F8F) +val light_tab_unselected_btn_background = light_background +val light_tab_unselected_btn_content = light_primary +val light_tab_selected_btn_content = light_background +val light_course_home_header_shade = Color(0xFFBABABA) +val light_course_home_back_btn_background = light_surface +val light_settings_title_content = light_surface +val light_progress_bar_color = light_primary_button_background +val light_progress_bar_background_color = light_secondary_variant + // Dark theme colors scheme val dark_primary = Color(0xFFFBFAF9) // Light 200 @@ -150,3 +159,12 @@ val dark_component_horizontal_progress_completed_and_selected = Color.White val dark_component_horizontal_progress_completed = Color(0xFF8F8F8F) val dark_component_horizontal_progress_selected = Color.White val dark_component_horizontal_progress_default = Color(0xFF8F8F8F) + +val dark_tab_unselected_btn_background = dark_background +val dark_tab_unselected_btn_content = dark_text_primary +val dark_tab_selected_btn_content = dark_background +val dark_course_home_header_shade = Color(0xFF999999) +val dark_course_home_back_btn_background = Color.Black +val dark_settings_title_content = Color.White +val dark_progress_bar_color = dark_primary_button_background +val dark_progress_bar_background_color = Color(0xFF8E9BAE) From 8b5722f9201d41a166bb344c8268ecffe78f2fff Mon Sep 17 00:00:00 2001 From: Farhan Arshad <43750646+farhan-arshad-dev@users.noreply.github.com> Date: Wed, 10 Jul 2024 13:12:20 +0500 Subject: [PATCH 32/38] feat: Payments and upgrade execution for the course (#1) * feat: Payments and upgrade execution for the course - Learners can purchase a course and unlock the gated content from the main dashboard - Loading course price on upgrade buttons successfully - Calling necessary APIs on interaction with the upgrade button - Processing the course upgrade - IAP Analytics fixes: LEARNER-9956 * feat: IAP for course dashboard * feat: added IAP UI views * feat: Add success message after upgrade - Code improvements & fixes * feat: handle UnfulfilledPurchase - In this case, the app relaunch must rerun the course upgrade flow with the available course upgrade data. fixes: LEARNER-9917 * feat: restore purchases from settings screen fixes: LEARNER-9915 * refactor: Error Alert Action Analytics Handling - fix IAP Analytics issues - Code improvements fixes: LEARNER-10042 * feat: update rocket icon for full screen loader - Full screen loader whille course is upgarding - Code improvements --------- Co-authored-by: k1rill --- .../java/org/openedx/app/AnalyticsManager.kt | 3 +- .../data/networking/HandleErrorInterceptor.kt | 8 +- .../main/java/org/openedx/app/di/AppModule.kt | 14 +- .../org/openedx/app/di/NetworkingModule.kt | 13 +- .../java/org/openedx/app/di/ScreenModule.kt | 43 +- build.gradle | 2 + core/build.gradle | 3 + .../java/org/openedx/core/ApiConstants.kt | 4 + .../java/org/openedx/core/config/Config.kt | 5 + .../core/data/api/iap/InAppPurchasesApi.kt | 33 ++ .../org/openedx/core/data/model/AppConfig.kt | 8 + .../core/data/model/CourseAccessDetails.kt | 22 + .../core/data/model/CourseEnrollments.kt | 6 + .../org/openedx/core/data/model/CourseMode.kt | 34 ++ .../core/data/model/CourseStructureModel.kt | 50 +- .../openedx/core/data/model/EnrolledCourse.kt | 21 +- .../core/data/model/EnrolledCourseData.kt | 6 +- .../core/data/model/EnrollmentDetails.kt | 37 ++ .../org/openedx/core/data/model/IAPConfig.kt | 28 ++ .../java/org/openedx/core/data/model/User.kt | 2 +- .../data/model/iap/AddToBasketResponse.kt | 13 + .../core/data/model/iap/CheckoutResponse.kt | 15 + .../data/model/iap/ExecuteOrderResponse.kt | 30 ++ .../data/model/room/CourseStructureEntity.kt | 19 +- .../room/discovery/EnrolledCourseEntity.kt | 43 +- .../core/data/repository/iap/IAPRepository.kt | 70 +++ .../core/domain/interactor/IAPInteractor.kt | 125 +++++ .../openedx/core/domain/model/AppConfig.kt | 8 + .../core/domain/model/CourseAccessDetails.kt | 11 + .../openedx/core/domain/model/CourseMode.kt | 11 + .../core/domain/model/CourseStructure.kt | 18 +- .../core/domain/model/CoursewareAccess.kt | 2 +- .../core/domain/model/EnrolledCourse.kt | 16 +- .../core/domain/model/EnrolledCourseData.kt | 13 +- .../core/domain/model/EnrollmentDetails.kt | 20 + .../core/domain/model/EnrollmentMode.kt | 14 + .../domain/model/iap/AddToBasketResponse.kt | 3 + .../core/domain/model/iap/CheckoutResponse.kt | 3 + .../domain/model/iap/ExecuteOrderResponse.kt | 3 + .../core/domain/model/iap/ProductInfo.kt | 10 + .../core/domain/model/iap/PurchaseFlowData.kt | 38 ++ .../core/exception/iap/IAPException.kt | 160 ++++++ .../openedx/core/extension/EncryptionExt.kt | 27 + .../org/openedx/core/extension/ViewExt.kt | 9 + .../core/module/billing/BillingProcessor.kt | 205 ++++++++ .../openedx/core/presentation/IAPAnalytics.kt | 70 +++ .../presentation/dialog/IAPDialogFragment.kt | 273 ++++++++++ .../presentation/iap/IAPErrorDialogType.kt | 110 ++++ .../core/presentation/iap/IAPUIState.kt | 61 +++ .../core/presentation/iap/IAPViewModel.kt | 366 ++++++++++++++ .../core/system/notifier/CourseDataUpdated.kt | 3 + .../openedx/core/system/notifier/IAPEvent.kt | 3 + .../core/system/notifier/IAPNotifier.kt | 14 + .../core/system/notifier/UpdateCourseData.kt | 3 + .../java/org/openedx/core/ui/ComposeCommon.kt | 2 + .../main/java/org/openedx/core/ui/IAPUI.kt | 472 ++++++++++++++++++ .../openedx/core/ui/UnlockingAccessView.kt | 83 +++ .../openedx/core/ui/UpgradeToAccessView.kt | 97 ++++ .../java/org/openedx/core/utils/TimeUtils.kt | 2 +- .../res/drawable/core_ic_rocket_launch.xml | 11 + core/src/main/res/values/strings.xml | 33 ++ .../container/CollapsingLayout.kt | 91 ++-- .../container/CourseContainerFragment.kt | 58 ++- .../container/CourseContainerViewModel.kt | 86 +++- .../outline/CourseOutlineScreen.kt | 38 +- .../outline/CourseOutlineViewModel.kt | 6 +- .../course/presentation/ui/CourseUI.kt | 10 +- .../course/presentation/ui/CourseVideosUI.kt | 30 +- .../container/CourseContainerViewModelTest.kt | 80 ++- .../dates/CourseDatesViewModelTest.kt | 17 +- .../outline/CourseOutlineViewModelTest.kt | 26 +- .../section/CourseSectionViewModelTest.kt | 29 +- .../CourseUnitContainerViewModelTest.kt | 29 +- .../videos/CourseVideoViewModelTest.kt | 166 +++--- .../presentation/MyCoursesScreenTest.kt | 43 +- .../presentation/AllEnrolledCoursesView.kt | 21 +- .../presentation/DashboardGalleryView.kt | 18 +- .../presentation/DashboardListFragment.kt | 162 +++++- .../presentation/DashboardListViewModel.kt | 142 +++++- .../presentation/DashboardUIState.kt | 4 +- .../presentation/DashboardViewModelTest.kt | 134 ++++- default_config/dev/config.yaml | 2 + default_config/prod/config.yaml | 2 + default_config/stage/config.yaml | 2 + .../topics/DiscussionTopicsViewModelTest.kt | 90 +++- .../presentation/settings/SettingsFragment.kt | 51 ++ .../presentation/settings/SettingsScreenUI.kt | 87 +++- .../settings/SettingsViewModel.kt | 101 +++- profile/src/main/res/values/strings.xml | 3 +- 89 files changed, 4006 insertions(+), 353 deletions(-) create mode 100644 core/src/main/java/org/openedx/core/data/api/iap/InAppPurchasesApi.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/CourseAccessDetails.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/CourseMode.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/EnrollmentDetails.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/IAPConfig.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/iap/AddToBasketResponse.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/iap/CheckoutResponse.kt create mode 100644 core/src/main/java/org/openedx/core/data/model/iap/ExecuteOrderResponse.kt create mode 100644 core/src/main/java/org/openedx/core/data/repository/iap/IAPRepository.kt create mode 100644 core/src/main/java/org/openedx/core/domain/interactor/IAPInteractor.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/CourseAccessDetails.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/CourseMode.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/EnrollmentDetails.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/EnrollmentMode.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/iap/AddToBasketResponse.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/iap/CheckoutResponse.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/iap/ExecuteOrderResponse.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/iap/ProductInfo.kt create mode 100644 core/src/main/java/org/openedx/core/domain/model/iap/PurchaseFlowData.kt create mode 100644 core/src/main/java/org/openedx/core/exception/iap/IAPException.kt create mode 100644 core/src/main/java/org/openedx/core/extension/EncryptionExt.kt create mode 100644 core/src/main/java/org/openedx/core/module/billing/BillingProcessor.kt create mode 100644 core/src/main/java/org/openedx/core/presentation/IAPAnalytics.kt create mode 100644 core/src/main/java/org/openedx/core/presentation/dialog/IAPDialogFragment.kt create mode 100644 core/src/main/java/org/openedx/core/presentation/iap/IAPErrorDialogType.kt create mode 100644 core/src/main/java/org/openedx/core/presentation/iap/IAPUIState.kt create mode 100644 core/src/main/java/org/openedx/core/presentation/iap/IAPViewModel.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/CourseDataUpdated.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/IAPEvent.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/IAPNotifier.kt create mode 100644 core/src/main/java/org/openedx/core/system/notifier/UpdateCourseData.kt create mode 100644 core/src/main/java/org/openedx/core/ui/IAPUI.kt create mode 100644 core/src/main/java/org/openedx/core/ui/UnlockingAccessView.kt create mode 100644 core/src/main/java/org/openedx/core/ui/UpgradeToAccessView.kt create mode 100644 core/src/main/res/drawable/core_ic_rocket_launch.xml diff --git a/app/src/main/java/org/openedx/app/AnalyticsManager.kt b/app/src/main/java/org/openedx/app/AnalyticsManager.kt index 9d8169863..b0adbcb22 100644 --- a/app/src/main/java/org/openedx/app/AnalyticsManager.kt +++ b/app/src/main/java/org/openedx/app/AnalyticsManager.kt @@ -8,6 +8,7 @@ import org.openedx.app.analytics.SegmentAnalytics import org.openedx.auth.presentation.AuthAnalytics import org.openedx.core.config.Config import org.openedx.core.presentation.CoreAnalytics +import org.openedx.core.presentation.IAPAnalytics import org.openedx.core.presentation.dialog.appreview.AppReviewAnalytics import org.openedx.course.presentation.CourseAnalytics import org.openedx.dashboard.presentation.DashboardAnalytics @@ -21,7 +22,7 @@ class AnalyticsManager( config: Config, ) : AppAnalytics, AppReviewAnalytics, AuthAnalytics, CoreAnalytics, CourseAnalytics, DashboardAnalytics, DiscoveryAnalytics, DiscussionAnalytics, ProfileAnalytics, - WhatsNewAnalytics { + WhatsNewAnalytics, IAPAnalytics { private val services: ArrayList = arrayListOf() diff --git a/app/src/main/java/org/openedx/app/data/networking/HandleErrorInterceptor.kt b/app/src/main/java/org/openedx/app/data/networking/HandleErrorInterceptor.kt index bd4aa1920..a4145d549 100644 --- a/app/src/main/java/org/openedx/app/data/networking/HandleErrorInterceptor.kt +++ b/app/src/main/java/org/openedx/app/data/networking/HandleErrorInterceptor.kt @@ -2,11 +2,11 @@ package org.openedx.app.data.networking import com.google.gson.Gson import com.google.gson.JsonSyntaxException -import org.openedx.core.data.model.ErrorResponse -import org.openedx.core.system.EdxError import okhttp3.Interceptor import okhttp3.Response import okio.IOException +import org.openedx.core.data.model.ErrorResponse +import org.openedx.core.system.EdxError class HandleErrorInterceptor( private val gson: Gson @@ -16,7 +16,7 @@ class HandleErrorInterceptor( val responseCode = response.code if (responseCode in 400..500 && response.body != null) { - val jsonStr = response.body!!.string() + val jsonStr = response.peekBody(Long.MAX_VALUE).string() try { val errorResponse = gson.fromJson(jsonStr, ErrorResponse::class.java) @@ -25,9 +25,11 @@ class HandleErrorInterceptor( ERROR_INVALID_GRANT -> { throw EdxError.InvalidGrantException() } + ERROR_USER_NOT_ACTIVE -> { throw EdxError.UserNotActiveException() } + else -> { return response } diff --git a/app/src/main/java/org/openedx/app/di/AppModule.kt b/app/src/main/java/org/openedx/app/di/AppModule.kt index 9e3a1709d..1f88bea73 100644 --- a/app/src/main/java/org/openedx/app/di/AppModule.kt +++ b/app/src/main/java/org/openedx/app/di/AppModule.kt @@ -12,10 +12,10 @@ import org.koin.core.qualifier.named import org.koin.dsl.module import org.openedx.app.AnalyticsManager import org.openedx.app.AppAnalytics -import org.openedx.app.deeplink.DeepLinkRouter import org.openedx.app.AppRouter import org.openedx.app.BuildConfig import org.openedx.app.data.storage.PreferencesManager +import org.openedx.app.deeplink.DeepLinkRouter import org.openedx.app.room.AppDatabase import org.openedx.app.room.DATABASE_NAME import org.openedx.auth.presentation.AgreementProvider @@ -28,12 +28,15 @@ import org.openedx.auth.presentation.sso.OAuthHelper import org.openedx.core.ImageProcessor import org.openedx.core.config.Config import org.openedx.core.data.model.CourseEnrollments +import org.openedx.core.data.model.CourseStructureModel import org.openedx.core.data.storage.CorePreferences import org.openedx.core.data.storage.InAppReviewPreferences import org.openedx.core.module.DownloadWorkerController import org.openedx.core.module.TranscriptManager +import org.openedx.core.module.billing.BillingProcessor import org.openedx.core.module.download.FileDownloader import org.openedx.core.presentation.CoreAnalytics +import org.openedx.core.presentation.IAPAnalytics import org.openedx.core.presentation.dialog.appreview.AppReviewAnalytics import org.openedx.core.presentation.dialog.appreview.AppReviewManager import org.openedx.core.presentation.global.AppData @@ -46,6 +49,7 @@ import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.core.system.notifier.DownloadNotifier +import org.openedx.core.system.notifier.IAPNotifier import org.openedx.core.system.notifier.VideoNotifier import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.core.utils.FileUtil @@ -88,6 +92,10 @@ val appModule = module { single { GsonBuilder() .registerTypeAdapter(CourseEnrollments::class.java, CourseEnrollments.Deserializer()) + .registerTypeAdapter( + CourseStructureModel::class.java, + CourseStructureModel.Deserializer(get()) + ) .create() } @@ -98,6 +106,7 @@ val appModule = module { single { DownloadNotifier() } single { VideoNotifier() } single { DiscoveryNotifier() } + single { IAPNotifier() } single { AppRouter() } single { get() } @@ -165,6 +174,8 @@ val appModule = module { single { WhatsNewManager(get(), get(), get(), get()) } single { get() } + single { BillingProcessor(get(), get(named("IODispatcher"))) } + single { AnalyticsManager(get(), get()) } single { get() } single { get() } @@ -176,6 +187,7 @@ val appModule = module { single { get() } single { get() } single { get() } + single { get() } factory { AgreementProvider(get(), get()) } factory { FacebookAuthHelper() } diff --git a/app/src/main/java/org/openedx/app/di/NetworkingModule.kt b/app/src/main/java/org/openedx/app/di/NetworkingModule.kt index aae32b433..be6b18916 100644 --- a/app/src/main/java/org/openedx/app/di/NetworkingModule.kt +++ b/app/src/main/java/org/openedx/app/di/NetworkingModule.kt @@ -2,6 +2,7 @@ package org.openedx.app.di import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor +import org.koin.core.qualifier.named import org.koin.dsl.module import org.openedx.app.data.api.NotificationsApi import org.openedx.app.data.networking.AppUpgradeInterceptor @@ -13,6 +14,7 @@ import org.openedx.core.BuildConfig import org.openedx.core.config.Config import org.openedx.core.data.api.CookiesApi import org.openedx.core.data.api.CourseApi +import org.openedx.core.data.api.iap.InAppPurchasesApi import org.openedx.discovery.data.api.DiscoveryApi import org.openedx.discussion.data.api.DiscussionApi import org.openedx.profile.data.api.ProfileApi @@ -48,6 +50,15 @@ val networkingModule = module { .build() } + single(named("IAPApiInstance")) { + val config = this.get() + Retrofit.Builder() + .baseUrl(config.getEcommerceURL()) + .client(get()) + .addConverterFactory(GsonConverterFactory.create(get())) + .build() + } + single { provideApi(get()) } single { provideApi(get()) } single { provideApi(get()) } @@ -55,9 +66,9 @@ val networkingModule = module { single { provideApi(get()) } single { provideApi(get()) } single { provideApi(get()) } + single { provideApi(get(named("IAPApiInstance"))) } } - inline fun provideApi(retrofit: Retrofit): T { return retrofit.create(T::class.java) } diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 429d048b9..d8d02314b 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -12,7 +12,12 @@ import org.openedx.auth.presentation.restore.RestorePasswordViewModel import org.openedx.auth.presentation.signin.SignInViewModel import org.openedx.auth.presentation.signup.SignUpViewModel import org.openedx.core.Validator +import org.openedx.core.data.repository.iap.IAPRepository +import org.openedx.core.domain.interactor.IAPInteractor +import org.openedx.core.domain.model.iap.PurchaseFlowData import org.openedx.core.presentation.dialog.selectorbottomsheet.SelectDialogViewModel +import org.openedx.core.presentation.iap.IAPFlow +import org.openedx.core.presentation.iap.IAPViewModel import org.openedx.core.presentation.settings.video.VideoQualityViewModel import org.openedx.core.ui.WindowSize import org.openedx.course.data.repository.CourseRepository @@ -133,7 +138,23 @@ val screenModule = module { factory { DashboardRepository(get(), get(), get(), get()) } factory { DashboardInteractor(get()) } - viewModel { DashboardListViewModel(get(), get(), get(), get(), get(), get(), get()) } + viewModel { + DashboardListViewModel( + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get() + ) + } + viewModel { (windowSize: WindowSize) -> DashboardGalleryViewModel( get(), @@ -190,6 +211,8 @@ val screenModule = module { get(), get(), get(), + get(), + get(), get() ) } @@ -240,6 +263,8 @@ val screenModule = module { get(), get(), get(), + get(), + get(), get() ) } @@ -415,6 +440,22 @@ val screenModule = module { ) } + single { IAPRepository(get()) } + factory { IAPInteractor(get(), get()) } + viewModel { (iapFlow: IAPFlow, purchaseFlowData: PurchaseFlowData) -> + IAPViewModel( + iapFlow = iapFlow, + purchaseFlowData = purchaseFlowData, + get(), + get(), + get(), + get(), + get(), + get(), + get() + ) + } + viewModel { (descendants: List) -> DownloadQueueViewModel( descendants, diff --git a/build.gradle b/build.gradle index c163d3982..3fbc54f22 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,8 @@ ext { webkit_version = "1.11.0" + billing_version = "6.2.1" + configHelper = new ConfigHelper(projectDir, getCurrentFlavor()) //testing diff --git a/core/build.gradle b/core/build.gradle index c18b5ad0c..1aed7f0a2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -165,6 +165,9 @@ dependencies { api "com.google.android.gms:play-services-ads-identifier:18.0.1" api "com.android.installreferrer:installreferrer:2.2" + // Google Play Billing Library + api "com.android.billingclient:billing-ktx:$billing_version" + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/core/src/main/java/org/openedx/core/ApiConstants.kt b/core/src/main/java/org/openedx/core/ApiConstants.kt index 786d63cc4..41192090e 100644 --- a/core/src/main/java/org/openedx/core/ApiConstants.kt +++ b/core/src/main/java/org/openedx/core/ApiConstants.kt @@ -34,4 +34,8 @@ object ApiConstants { const val HONOR_CODE = "honor_code" const val MARKETING_EMAILS = "marketing_emails_opt_in" } + + object IAPFields { + const val PAYMENT_PROCESSOR = "android-iap" + } } diff --git a/core/src/main/java/org/openedx/core/config/Config.kt b/core/src/main/java/org/openedx/core/config/Config.kt index 528ff4cc8..6c495a569 100644 --- a/core/src/main/java/org/openedx/core/config/Config.kt +++ b/core/src/main/java/org/openedx/core/config/Config.kt @@ -27,6 +27,10 @@ class Config(context: Context) { return getString(API_HOST_URL) } + fun getEcommerceURL(): String { + return getString(ECOMMERCE_URL, "") + } + fun getUriScheme(): String { return getString(URI_SCHEME) } @@ -152,6 +156,7 @@ class Config(context: Context) { companion object { private const val APPLICATION_ID = "APPLICATION_ID" private const val API_HOST_URL = "API_HOST_URL" + private const val ECOMMERCE_URL = "ECOMMERCE_URL" private const val URI_SCHEME = "URI_SCHEME" private const val OAUTH_CLIENT_ID = "OAUTH_CLIENT_ID" private const val TOKEN_TYPE = "TOKEN_TYPE" diff --git a/core/src/main/java/org/openedx/core/data/api/iap/InAppPurchasesApi.kt b/core/src/main/java/org/openedx/core/data/api/iap/InAppPurchasesApi.kt new file mode 100644 index 000000000..4730d3922 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/api/iap/InAppPurchasesApi.kt @@ -0,0 +1,33 @@ +package org.openedx.core.data.api.iap + +import org.openedx.core.data.model.iap.AddToBasketResponse +import org.openedx.core.data.model.iap.CheckoutResponse +import org.openedx.core.data.model.iap.ExecuteOrderResponse +import retrofit2.Response +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +interface InAppPurchasesApi { + @GET("/api/iap/v1/basket/add/") + suspend fun addToBasket(@Query("sku") productId: String): Response + + @FormUrlEncoded + @POST("/api/iap/v1/checkout/") + suspend fun proceedCheckout( + @Field("basket_id") basketId: Long, + @Field("payment_processor") paymentProcessor: String + ): Response + + @FormUrlEncoded + @POST("/api/iap/v1/execute/") + suspend fun executeOrder( + @Field("basket_id") basketId: Long, + @Field("payment_processor") paymentProcessor: String, + @Field("purchase_token") purchaseToken: String, + @Field("price") price: Double, + @Field("currency_code") currencyCode: String, + ): Response +} diff --git a/core/src/main/java/org/openedx/core/data/model/AppConfig.kt b/core/src/main/java/org/openedx/core/data/model/AppConfig.kt index 4fcbe3d89..218a35a4e 100644 --- a/core/src/main/java/org/openedx/core/data/model/AppConfig.kt +++ b/core/src/main/java/org/openedx/core/data/model/AppConfig.kt @@ -6,10 +6,18 @@ import org.openedx.core.domain.model.AppConfig as DomainAppConfig data class AppConfig( @SerializedName("course_dates_calendar_sync") val calendarSyncConfig: CalendarSyncConfig = CalendarSyncConfig(), + + @SerializedName("value_prop_enabled") + val isValuePropEnabled: Boolean = false, + + @SerializedName("iap_config") + val iapConfig: IAPConfig = IAPConfig(), ) { fun mapToDomain(): DomainAppConfig { return DomainAppConfig( courseDatesCalendarSync = calendarSyncConfig.mapToDomain(), + isValuePropEnabled = isValuePropEnabled, + iapConfig = iapConfig.mapToDomain(), ) } } diff --git a/core/src/main/java/org/openedx/core/data/model/CourseAccessDetails.kt b/core/src/main/java/org/openedx/core/data/model/CourseAccessDetails.kt new file mode 100644 index 000000000..1b4275f08 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/CourseAccessDetails.kt @@ -0,0 +1,22 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.data.model.room.discovery.CourseAccessDetailsDb +import org.openedx.core.utils.TimeUtils +import org.openedx.core.domain.model.CourseAccessDetails as DomainCourseAccessDetails + +data class CourseAccessDetails( + @SerializedName("audit_access_expires") + val auditAccessExpires: String?, + @SerializedName("courseware_access") + var coursewareAccess: CoursewareAccess?, +) { + fun mapToDomain(): DomainCourseAccessDetails = + DomainCourseAccessDetails( + TimeUtils.iso8601ToDate(auditAccessExpires ?: ""), + coursewareAccess?.mapToDomain() + ) + + fun mapToRoomEntity(): CourseAccessDetailsDb = + CourseAccessDetailsDb(auditAccessExpires, coursewareAccess?.mapToRoomEntity()) +} diff --git a/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt b/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt index ca28740fe..2682f957c 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseEnrollments.kt @@ -35,6 +35,12 @@ data class CourseEnrollments( val appConfig = deserializeAppConfig(json) val primaryCourse = deserializePrimaryCourse(json) + if (appConfig.iapConfig.productPrefix.isNotEmpty()) { + enrollments.results.forEach { courseData -> + courseData.setStoreSku(appConfig.iapConfig.productPrefix) + } + } + return CourseEnrollments(enrollments, appConfig, primaryCourse) } diff --git a/core/src/main/java/org/openedx/core/data/model/CourseMode.kt b/core/src/main/java/org/openedx/core/data/model/CourseMode.kt new file mode 100644 index 000000000..d534d67a4 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/CourseMode.kt @@ -0,0 +1,34 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import kotlin.math.ceil + +/** + * Data class representing the mode of a course ("audit, verified etc"), with various attributes + * related to its identification and pricing. + * */ +data class CourseMode( + @SerializedName("slug") + val slug: String?, + + @SerializedName("sku") + val sku: String?, + + @SerializedName("android_sku") + val androidSku: String?, + + @SerializedName("min_price") + val price: Double?, + + var storeSku: String?, +) { + fun setStoreProductSku(storeProductPrefix: String) { + val ceilPrice = price + ?.let { ceil(it).toInt() } + ?.takeIf { it > 0 } + + if (storeProductPrefix.isNotBlank() && ceilPrice != null) { + storeSku = "$storeProductPrefix$ceilPrice" + } + } +} diff --git a/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt b/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt index d09411d14..1fca6e677 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseStructureModel.kt @@ -1,12 +1,20 @@ package org.openedx.core.data.model +import com.google.gson.Gson +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement import com.google.gson.annotations.SerializedName import org.openedx.core.data.model.room.BlockDb import org.openedx.core.data.model.room.CourseStructureEntity import org.openedx.core.data.model.room.MediaDb import org.openedx.core.data.model.room.discovery.ProgressDb +import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.CourseStructure +import org.openedx.core.domain.model.EnrollmentMode +import org.openedx.core.domain.model.iap.ProductInfo import org.openedx.core.utils.TimeUtils +import java.lang.reflect.Type data class CourseStructureModel( @SerializedName("root") @@ -29,16 +37,20 @@ data class CourseStructureModel( var startType: String?, @SerializedName("end") var end: String?, - @SerializedName("courseware_access") - var coursewareAccess: CoursewareAccess?, @SerializedName("media") var media: Media?, + @SerializedName("course_access_details") + val courseAccessDetails: CourseAccessDetails, @SerializedName("certificate") val certificate: Certificate?, + @SerializedName("enrollment_details") + val enrollmentDetails: EnrollmentDetails, @SerializedName("is_self_paced") var isSelfPaced: Boolean?, @SerializedName("course_progress") val progress: Progress?, + @SerializedName("course_modes") + val courseModes: List?, ) { fun mapToDomain(): CourseStructure { return CourseStructure( @@ -54,11 +66,19 @@ data class CourseStructureModel( startDisplay = startDisplay ?: "", startType = startType ?: "", end = TimeUtils.iso8601ToDate(end ?: ""), - coursewareAccess = coursewareAccess?.mapToDomain(), media = media?.mapToDomain(), + courseAccessDetails = courseAccessDetails.mapToDomain(), certificate = certificate?.mapToDomain(), isSelfPaced = isSelfPaced ?: false, - progress = progress?.mapToDomain() + progress = progress?.mapToDomain(), + enrollmentDetails = enrollmentDetails.mapToDomain(), + productInfo = courseModes?.find { + EnrollmentMode.VERIFIED.toString().equals(it.slug, ignoreCase = true) + }?.takeIf { + it.androidSku.isNullOrEmpty().not() && it.storeSku.isNullOrEmpty().not() + }?.run { + ProductInfo(courseSku = androidSku!!, storeSku = storeSku!!) + } ) } @@ -74,11 +94,29 @@ data class CourseStructureModel( startDisplay = startDisplay ?: "", startType = startType ?: "", end = end ?: "", - coursewareAccess = coursewareAccess?.mapToRoomEntity(), media = MediaDb.createFrom(media), + courseAccessDetails = courseAccessDetails.mapToRoomEntity(), certificate = certificate?.mapToRoomEntity(), isSelfPaced = isSelfPaced ?: false, - progress = progress?.mapToRoomEntity() ?: ProgressDb.DEFAULT_PROGRESS + progress = progress?.mapToRoomEntity() ?: ProgressDb.DEFAULT_PROGRESS, + enrollmentDetails = enrollmentDetails.mapToRoomEntity() ) } + + class Deserializer(val corePreferences: CorePreferences) : + JsonDeserializer { + override fun deserialize( + json: JsonElement?, + typeOfT: Type?, + context: JsonDeserializationContext? + ): CourseStructureModel { + val courseStructure = Gson().fromJson(json, CourseStructureModel::class.java) + if (corePreferences.appConfig.iapConfig.productPrefix.isNullOrEmpty().not()) { + courseStructure.courseModes?.forEach { courseModes -> + courseModes.setStoreProductSku(corePreferences.appConfig.iapConfig.productPrefix!!) + } + } + return courseStructure + } + } } diff --git a/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt b/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt index edf8bbce3..54aa5e88a 100644 --- a/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt +++ b/core/src/main/java/org/openedx/core/data/model/EnrolledCourse.kt @@ -4,6 +4,8 @@ import com.google.gson.annotations.SerializedName import org.openedx.core.data.model.room.discovery.EnrolledCourseEntity import org.openedx.core.data.model.room.discovery.ProgressDb import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.domain.model.EnrollmentMode +import org.openedx.core.domain.model.iap.ProductInfo import org.openedx.core.utils.TimeUtils import org.openedx.core.domain.model.Progress as ProgressDomain @@ -25,7 +27,9 @@ data class EnrolledCourse( @SerializedName("course_status") val courseStatus: CourseStatus?, @SerializedName("course_assignments") - val courseAssignments: CourseAssignments? + val courseAssignments: CourseAssignments?, + @SerializedName("course_modes") + val courseModes: List?, ) { fun mapToDomain(): EnrolledCourse { return EnrolledCourse( @@ -37,7 +41,14 @@ data class EnrolledCourse( certificate = certificate?.mapToDomain(), progress = progress?.mapToDomain() ?: ProgressDomain.DEFAULT_PROGRESS, courseStatus = courseStatus?.mapToDomain(), - courseAssignments = courseAssignments?.mapToDomain() + courseAssignments = courseAssignments?.mapToDomain(), + productInfo = courseModes?.find { + EnrollmentMode.VERIFIED.toString().equals(it.slug, ignoreCase = true) + }?.takeIf { + it.androidSku.isNullOrEmpty().not() && it.storeSku.isNullOrEmpty().not() + }?.run { + ProductInfo(courseSku = androidSku!!, storeSku = storeSku!!) + } ) } @@ -55,4 +66,10 @@ data class EnrolledCourse( courseAssignments = courseAssignments?.mapToRoomEntity() ) } + + fun setStoreSku(storeProductPrefix: String) { + courseModes?.forEach { + it.setStoreProductSku(storeProductPrefix) + } + } } diff --git a/core/src/main/java/org/openedx/core/data/model/EnrolledCourseData.kt b/core/src/main/java/org/openedx/core/data/model/EnrolledCourseData.kt index 4afc9ef71..714707d88 100644 --- a/core/src/main/java/org/openedx/core/data/model/EnrolledCourseData.kt +++ b/core/src/main/java/org/openedx/core/data/model/EnrolledCourseData.kt @@ -24,7 +24,7 @@ data class EnrolledCourseData( @SerializedName("end") var end: String?, @SerializedName("dynamic_upgrade_deadline") - var dynamicUpgradeDeadline: String?, + var upgradeDeadline: String?, @SerializedName("subscription_id") var subscriptionId: String?, @SerializedName("courseware_access") @@ -59,7 +59,7 @@ data class EnrolledCourseData( startDisplay = startDisplay ?: "", startType = startType ?: "", end = TimeUtils.iso8601ToDate(end ?: ""), - dynamicUpgradeDeadline = dynamicUpgradeDeadline ?: "", + upgradeDeadline = upgradeDeadline ?: "", subscriptionId = subscriptionId ?: "", coursewareAccess = coursewareAccess?.mapToDomain(), media = media?.mapToDomain(), @@ -84,7 +84,7 @@ data class EnrolledCourseData( startDisplay = startDisplay ?: "", startType = startType ?: "", end = end ?: "", - dynamicUpgradeDeadline = dynamicUpgradeDeadline ?: "", + upgradeDeadline = upgradeDeadline ?: "", subscriptionId = subscriptionId ?: "", coursewareAccess = coursewareAccess?.mapToRoomEntity(), media = MediaDb.createFrom(media), diff --git a/core/src/main/java/org/openedx/core/data/model/EnrollmentDetails.kt b/core/src/main/java/org/openedx/core/data/model/EnrollmentDetails.kt new file mode 100644 index 000000000..e1172d713 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/EnrollmentDetails.kt @@ -0,0 +1,37 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.data.model.room.discovery.EnrollmentDetailsDB +import org.openedx.core.utils.TimeUtils + +import org.openedx.core.domain.model.EnrollmentDetails as DomainEnrollmentDetails + +data class EnrollmentDetails( + @SerializedName("created") + var created: String?, + + @SerializedName("mode") + var mode: String?, + + @SerializedName("is_active") + var isActive: Boolean = false, + + @SerializedName("upgrade_deadline") + var upgradeDeadline: String?, +) { + fun mapToDomain(): DomainEnrollmentDetails { + return DomainEnrollmentDetails( + created = TimeUtils.iso8601ToDate(created ?: ""), + mode = mode, + isActive = isActive, + upgradeDeadline = TimeUtils.iso8601ToDate(upgradeDeadline ?: ""), + ) + } + + fun mapToRoomEntity() = EnrollmentDetailsDB( + created = created, + mode = mode, + isActive = isActive, + upgradeDeadline = upgradeDeadline, + ) +} diff --git a/core/src/main/java/org/openedx/core/data/model/IAPConfig.kt b/core/src/main/java/org/openedx/core/data/model/IAPConfig.kt new file mode 100644 index 000000000..2e9a78d91 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/IAPConfig.kt @@ -0,0 +1,28 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.domain.model.IAPConfig as DomainIAPConfig + +/** + * Model class that contains the Config related to In App Purchases. + */ +data class IAPConfig( + + @SerializedName("enabled") + val isEnabled: Boolean = false, + + @SerializedName("android_product_prefix") + val productPrefix: String = "", + + @SerializedName("android_disabled_versions") + val disableVersions: List = listOf() + +) { + fun mapToDomain(): DomainIAPConfig { + return DomainIAPConfig( + isEnabled = isEnabled, + productPrefix = productPrefix, + disableVersions = disableVersions + ) + } +} diff --git a/core/src/main/java/org/openedx/core/data/model/User.kt b/core/src/main/java/org/openedx/core/data/model/User.kt index 99194624b..fbff8eced 100644 --- a/core/src/main/java/org/openedx/core/data/model/User.kt +++ b/core/src/main/java/org/openedx/core/data/model/User.kt @@ -15,7 +15,7 @@ data class User( ) { fun mapToDomain(): User { return User( - id, username, email, name?:"" + id, username, email, name ?: "" ) } } diff --git a/core/src/main/java/org/openedx/core/data/model/iap/AddToBasketResponse.kt b/core/src/main/java/org/openedx/core/data/model/iap/AddToBasketResponse.kt new file mode 100644 index 000000000..6f7133ffe --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/iap/AddToBasketResponse.kt @@ -0,0 +1,13 @@ +package org.openedx.core.data.model.iap + +import com.google.gson.annotations.SerializedName +import org.openedx.core.domain.model.iap.AddToBasketResponse as AddToBasketResponseDomain + +data class AddToBasketResponse( + @SerializedName("success") val success: String, + @SerializedName("basket_id") val basketId: Long +) { + fun mapToDomain(): AddToBasketResponseDomain { + return AddToBasketResponseDomain(basketId) + } +} diff --git a/core/src/main/java/org/openedx/core/data/model/iap/CheckoutResponse.kt b/core/src/main/java/org/openedx/core/data/model/iap/CheckoutResponse.kt new file mode 100644 index 000000000..1478df34a --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/iap/CheckoutResponse.kt @@ -0,0 +1,15 @@ +package org.openedx.core.data.model.iap + +import com.google.gson.annotations.SerializedName +import org.openedx.core.domain.model.iap.CheckoutResponse as CheckoutResponseDomain + + +data class CheckoutResponse( + @SerializedName("payment_form_data") val paymentFormData: MutableMap, + @SerializedName("payment_page_url") val paymentPageUrl: String, + @SerializedName("payment_processor") val paymentProcessor: String +) { + fun mapToDomain(): CheckoutResponseDomain { + return CheckoutResponseDomain + } +} diff --git a/core/src/main/java/org/openedx/core/data/model/iap/ExecuteOrderResponse.kt b/core/src/main/java/org/openedx/core/data/model/iap/ExecuteOrderResponse.kt new file mode 100644 index 000000000..9ba9d4890 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/iap/ExecuteOrderResponse.kt @@ -0,0 +1,30 @@ +package org.openedx.core.data.model.iap + +import com.google.gson.annotations.SerializedName +import org.openedx.core.domain.model.iap.ExecuteOrderResponse +import org.openedx.core.domain.model.iap.ExecuteOrderResponse as ExecuteOrderResponseDomain + +data class ExecuteOrderResponse( + @SerializedName("order_data") val orderData: OrderData +) { + fun mapToDomain(): ExecuteOrderResponse { + return ExecuteOrderResponseDomain + } +} + +data class OrderData( + @SerializedName("billing_address") val billingAddress: String, + @SerializedName("currency") val currency: String, + @SerializedName("date_placed") val datePlaced: String, + @SerializedName("discount") val discount: String, + @SerializedName("number") val number: String, + @SerializedName("payment_processor") val paymentProcessor: String, + @SerializedName("status") val status: String, + @SerializedName("total_excl_tax") val totalExclTax: String, + @SerializedName("user") val user: User +) + +data class User( + @SerializedName("email") val email: String, + @SerializedName("username") val username: String +) diff --git a/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt b/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt index 49862d683..d9e50711a 100644 --- a/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt +++ b/core/src/main/java/org/openedx/core/data/model/room/CourseStructureEntity.kt @@ -5,7 +5,8 @@ import androidx.room.Embedded import androidx.room.Entity import androidx.room.PrimaryKey import org.openedx.core.data.model.room.discovery.CertificateDb -import org.openedx.core.data.model.room.discovery.CoursewareAccessDb +import org.openedx.core.data.model.room.discovery.CourseAccessDetailsDb +import org.openedx.core.data.model.room.discovery.EnrollmentDetailsDB import org.openedx.core.data.model.room.discovery.ProgressDb import org.openedx.core.domain.model.CourseStructure import org.openedx.core.utils.TimeUtils @@ -34,17 +35,18 @@ data class CourseStructureEntity( @ColumnInfo("end") val end: String?, @Embedded - val coursewareAccess: CoursewareAccessDb?, - @Embedded val media: MediaDb?, @Embedded + val courseAccessDetails: CourseAccessDetailsDb, + @Embedded val certificate: CertificateDb?, + @Embedded + val enrollmentDetails: EnrollmentDetailsDB, @ColumnInfo("isSelfPaced") val isSelfPaced: Boolean, @Embedded val progress: ProgressDb, ) { - fun mapToDomain(): CourseStructure { return CourseStructure( root, @@ -57,12 +59,13 @@ data class CourseStructureEntity( startDisplay, startType, TimeUtils.iso8601ToDate(end ?: ""), - coursewareAccess?.mapToDomain(), media?.mapToDomain(), + courseAccessDetails.mapToDomain(), certificate?.mapToDomain(), isSelfPaced, - progress.mapToDomain() + progress.mapToDomain(), + enrollmentDetails.mapToDomain(), + null, ) } - -} \ No newline at end of file +} diff --git a/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt b/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt index e019f6300..fce33e00d 100644 --- a/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt +++ b/core/src/main/java/org/openedx/core/data/model/room/discovery/EnrolledCourseEntity.kt @@ -7,6 +7,7 @@ import androidx.room.PrimaryKey import org.openedx.core.data.model.DateType import org.openedx.core.data.model.room.MediaDb import org.openedx.core.domain.model.Certificate +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseAssignments import org.openedx.core.domain.model.CourseDateBlock import org.openedx.core.domain.model.CourseSharingUtmParameters @@ -14,6 +15,7 @@ import org.openedx.core.domain.model.CourseStatus import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.EnrolledCourse import org.openedx.core.domain.model.EnrolledCourseData +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.domain.model.Progress import org.openedx.core.utils.TimeUtils import java.util.Date @@ -53,7 +55,8 @@ data class EnrolledCourseEntity( certificate?.mapToDomain(), progress.mapToDomain(), courseStatus?.mapToDomain(), - courseAssignments?.mapToDomain() + courseAssignments?.mapToDomain(), + null ) } } @@ -75,8 +78,8 @@ data class EnrolledCourseDataDb( val startType: String, @ColumnInfo("end") val end: String, - @ColumnInfo("dynamicUpgradeDeadline") - val dynamicUpgradeDeadline: String, + @ColumnInfo("upgradeDeadline") + val upgradeDeadline: String, @ColumnInfo("subscriptionId") val subscriptionId: String, @Embedded @@ -110,7 +113,7 @@ data class EnrolledCourseDataDb( startDisplay, startType, TimeUtils.iso8601ToDate(end), - dynamicUpgradeDeadline, + upgradeDeadline, subscriptionId, coursewareAccess?.mapToDomain(), media?.mapToDomain(), @@ -244,3 +247,35 @@ data class CourseDateBlockDb( assignmentType = assignmentType ) } + +data class EnrollmentDetailsDB( + @ColumnInfo("created") + var created: String?, + @ColumnInfo("mode") + var mode: String?, + @ColumnInfo("isActive") + var isActive: Boolean, + @ColumnInfo("upgradeDeadline") + var upgradeDeadline: String?, +) { + fun mapToDomain() = EnrollmentDetails( + TimeUtils.iso8601ToDate(created ?: ""), + mode, + isActive, + TimeUtils.iso8601ToDate(upgradeDeadline ?: "") + ) +} + +data class CourseAccessDetailsDb( + @ColumnInfo("auditAccessExpires") + var auditAccessExpires: String?, + @Embedded + val coursewareAccess: CoursewareAccessDb?, +) { + fun mapToDomain(): CourseAccessDetails { + return CourseAccessDetails( + TimeUtils.iso8601ToDate(auditAccessExpires ?: ""), + coursewareAccess?.mapToDomain() + ) + } +} diff --git a/core/src/main/java/org/openedx/core/data/repository/iap/IAPRepository.kt b/core/src/main/java/org/openedx/core/data/repository/iap/IAPRepository.kt new file mode 100644 index 000000000..a4b28600a --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/repository/iap/IAPRepository.kt @@ -0,0 +1,70 @@ +package org.openedx.core.data.repository.iap + +import org.openedx.core.ApiConstants +import org.openedx.core.data.api.iap.InAppPurchasesApi +import org.openedx.core.domain.model.iap.AddToBasketResponse +import org.openedx.core.domain.model.iap.CheckoutResponse +import org.openedx.core.domain.model.iap.ExecuteOrderResponse +import org.openedx.core.exception.iap.IAPException +import org.openedx.core.exception.iap.getMessage +import org.openedx.core.presentation.iap.IAPRequestType + +class IAPRepository(private val api: InAppPurchasesApi) { + + suspend fun addToBasket(courseSku: String): AddToBasketResponse { + val response = api.addToBasket(courseSku) + if (response.isSuccessful) { + response.body()?.run { + return mapToDomain() + } + } + throw IAPException( + requestType = IAPRequestType.ADD_TO_BASKET_CODE, + httpErrorCode = response.code(), + errorMessage = response.getMessage() + ) + } + + suspend fun proceedCheckout(basketId: Long): CheckoutResponse { + val response = api.proceedCheckout( + basketId = basketId, + paymentProcessor = ApiConstants.IAPFields.PAYMENT_PROCESSOR + ) + if (response.isSuccessful) { + response.body()?.run { + return mapToDomain() + } + } + throw IAPException( + requestType = IAPRequestType.CHECKOUT_CODE, + httpErrorCode = response.code(), + errorMessage = response.getMessage() + ) + } + + suspend fun executeOrder( + basketId: Long, + paymentProcessor: String, + purchaseToken: String, + price: Double, + currencyCode: String, + ): ExecuteOrderResponse { + val response = api.executeOrder( + basketId = basketId, + paymentProcessor = paymentProcessor, + purchaseToken = purchaseToken, + price = price, + currencyCode = currencyCode + ) + if (response.isSuccessful) { + response.body()?.run { + return mapToDomain() + } + } + throw IAPException( + requestType = IAPRequestType.EXECUTE_ORDER_CODE, + httpErrorCode = response.code(), + errorMessage = response.getMessage() + ) + } +} diff --git a/core/src/main/java/org/openedx/core/domain/interactor/IAPInteractor.kt b/core/src/main/java/org/openedx/core/domain/interactor/IAPInteractor.kt new file mode 100644 index 000000000..b1f2e2762 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/interactor/IAPInteractor.kt @@ -0,0 +1,125 @@ +package org.openedx.core.domain.interactor + +import androidx.fragment.app.FragmentActivity +import com.android.billingclient.api.BillingClient.BillingResponseCode +import com.android.billingclient.api.ProductDetails +import com.android.billingclient.api.Purchase +import org.openedx.core.ApiConstants +import org.openedx.core.data.repository.iap.IAPRepository +import org.openedx.core.domain.model.iap.ProductInfo +import org.openedx.core.exception.iap.IAPException +import org.openedx.core.extension.decodeToLong +import org.openedx.core.module.billing.BillingProcessor +import org.openedx.core.module.billing.getCourseSku +import org.openedx.core.module.billing.getPriceAmount +import org.openedx.core.presentation.iap.IAPRequestType + +class IAPInteractor( + private val billingProcessor: BillingProcessor, + private val repository: IAPRepository, +) { + suspend fun loadPrice(productId: String): ProductDetails.OneTimePurchaseOfferDetails { + val response = billingProcessor.querySyncDetails(productId) + val productDetails = response.productDetailsList?.firstOrNull()?.oneTimePurchaseOfferDetails + val billingResult = response.billingResult + + if (billingResult.responseCode == BillingResponseCode.OK) { + if (productDetails != null) { + return productDetails + } else { + throw IAPException( + requestType = IAPRequestType.NO_SKU_CODE, + httpErrorCode = billingResult.responseCode, + errorMessage = billingResult.debugMessage + ) + } + } else { + throw IAPException( + requestType = IAPRequestType.PRICE_CODE, + httpErrorCode = billingResult.responseCode, + errorMessage = billingResult.debugMessage + ) + } + } + + suspend fun addToBasket(courseSku: String): Long { + val basketResponse = repository.addToBasket(courseSku) + return basketResponse.basketId + } + + suspend fun processCheckout(basketId: Long) { + repository.proceedCheckout(basketId) + } + + suspend fun purchaseItem( + activity: FragmentActivity, + id: Long, + productInfo: ProductInfo, + purchaseListeners: BillingProcessor.PurchaseListeners, + ) { + billingProcessor.setPurchaseListener(purchaseListeners) + billingProcessor.purchaseItem(activity, id, productInfo) + } + + suspend fun executeOrder( + basketId: Long, + purchaseToken: String, + price: Double, + currencyCode: String + ) { + repository.executeOrder( + basketId = basketId, + paymentProcessor = ApiConstants.IAPFields.PAYMENT_PROCESSOR, + purchaseToken = purchaseToken, + price = price, + currencyCode = currencyCode, + ) + } + + suspend fun consumePurchase(purchaseToken: String) { + val result = billingProcessor.consumePurchase(purchaseToken) + if (result.responseCode != BillingResponseCode.OK) { + throw IAPException( + requestType = IAPRequestType.CONSUME_CODE, + httpErrorCode = result.responseCode, + errorMessage = result.debugMessage + ) + } + } + + suspend fun processUnfulfilledPurchase(userId: Long): Boolean { + val purchases = billingProcessor.queryPurchases() + val userPurchases = + purchases.filter { it.accountIdentifiers?.obfuscatedAccountId?.decodeToLong() == userId } + if (userPurchases.isNotEmpty()) { + startUnfulfilledVerification(userPurchases) + return true + } else { + purchases.forEach { + billingProcessor.consumePurchase(it.purchaseToken) + } + } + return false + } + + private suspend fun startUnfulfilledVerification(userPurchases: List) { + userPurchases.forEach { purchase -> + val productDetail = + billingProcessor.querySyncDetails(purchase.products.first()).productDetailsList?.firstOrNull() + productDetail?.oneTimePurchaseOfferDetails?.takeIf { + purchase.getCourseSku().isNullOrEmpty().not() + }?.let { oneTimeProductDetails -> + val courseSku = purchase.getCourseSku() ?: return@let + val basketId = addToBasket(courseSku) + processCheckout(basketId) + executeOrder( + basketId = basketId, + purchaseToken = purchase.purchaseToken, + price = oneTimeProductDetails.getPriceAmount(), + currencyCode = oneTimeProductDetails.priceCurrencyCode, + ) + consumePurchase(purchase.purchaseToken) + } + } + } +} diff --git a/core/src/main/java/org/openedx/core/domain/model/AppConfig.kt b/core/src/main/java/org/openedx/core/domain/model/AppConfig.kt index 596fd0619..17ef4a5c5 100644 --- a/core/src/main/java/org/openedx/core/domain/model/AppConfig.kt +++ b/core/src/main/java/org/openedx/core/domain/model/AppConfig.kt @@ -4,6 +4,8 @@ import java.io.Serializable data class AppConfig( val courseDatesCalendarSync: CourseDatesCalendarSync, + val isValuePropEnabled: Boolean = false, + val iapConfig: IAPConfig = IAPConfig(), ) : Serializable data class CourseDatesCalendarSync( @@ -12,3 +14,9 @@ data class CourseDatesCalendarSync( val isInstructorPacedEnabled: Boolean, val isDeepLinkEnabled: Boolean, ) : Serializable + +data class IAPConfig( + val isEnabled: Boolean = false, + val productPrefix: String? = null, + val disableVersions: List = listOf() +) : Serializable diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseAccessDetails.kt b/core/src/main/java/org/openedx/core/domain/model/CourseAccessDetails.kt new file mode 100644 index 000000000..d7246d2e1 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/CourseAccessDetails.kt @@ -0,0 +1,11 @@ +package org.openedx.core.domain.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize +import java.util.Date + +@Parcelize +data class CourseAccessDetails( + val auditAccessExpires: Date?, + val coursewareAccess: CoursewareAccess?, +) : Parcelable diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseMode.kt b/core/src/main/java/org/openedx/core/domain/model/CourseMode.kt new file mode 100644 index 000000000..8803c4ce2 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/CourseMode.kt @@ -0,0 +1,11 @@ +package org.openedx.core.domain.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class CourseMode( + val slug: String?, + val androidSku: String?, + var storeSku: String?, +) : Parcelable diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt b/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt index 4ba3a8419..8430dfdaf 100644 --- a/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt +++ b/core/src/main/java/org/openedx/core/domain/model/CourseStructure.kt @@ -1,5 +1,7 @@ package org.openedx.core.domain.model +import org.openedx.core.domain.model.iap.ProductInfo +import org.openedx.core.utils.TimeUtils import java.util.Date data class CourseStructure( @@ -13,9 +15,21 @@ data class CourseStructure( val startDisplay: String, val startType: String, val end: Date?, - val coursewareAccess: CoursewareAccess?, val media: Media?, + val courseAccessDetails: CourseAccessDetails, val certificate: Certificate?, val isSelfPaced: Boolean, val progress: Progress?, -) + val enrollmentDetails: EnrollmentDetails, + val productInfo: ProductInfo? +) { + private val isStarted: Boolean + get() = TimeUtils.isDatePassed(Date(), start) + + val isUpgradeable: Boolean + get() = enrollmentDetails.isAuditMode && + isStarted && + courseAccessDetails.coursewareAccess?.hasAccess == true && + enrollmentDetails.isUpgradeDeadlinePassed.not() && + productInfo != null +} diff --git a/core/src/main/java/org/openedx/core/domain/model/CoursewareAccess.kt b/core/src/main/java/org/openedx/core/domain/model/CoursewareAccess.kt index 187c995b6..5dd48d94e 100644 --- a/core/src/main/java/org/openedx/core/domain/model/CoursewareAccess.kt +++ b/core/src/main/java/org/openedx/core/domain/model/CoursewareAccess.kt @@ -11,4 +11,4 @@ data class CoursewareAccess( val userMessage: String, val additionalContextUserMessage: String, val userFragment: String -) : Parcelable \ No newline at end of file +) : Parcelable diff --git a/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt b/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt index 184fc3aa4..7cbc6811c 100644 --- a/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt +++ b/core/src/main/java/org/openedx/core/domain/model/EnrolledCourse.kt @@ -2,6 +2,7 @@ package org.openedx.core.domain.model import android.os.Parcelable import kotlinx.parcelize.Parcelize +import org.openedx.core.domain.model.iap.ProductInfo import java.util.Date @Parcelize @@ -14,5 +15,16 @@ data class EnrolledCourse( val certificate: Certificate?, val progress: Progress, val courseStatus: CourseStatus?, - val courseAssignments: CourseAssignments? -) : Parcelable + val courseAssignments: CourseAssignments?, + val productInfo: ProductInfo?, +) : Parcelable { + + private val isAuditMode: Boolean + get() = EnrollmentMode.AUDIT.toString().equals(mode, ignoreCase = true) + + val isUpgradeable: Boolean + get() = isAuditMode && + course.isStarted && + course.isUpgradeDeadlinePassed.not() && + productInfo != null +} diff --git a/core/src/main/java/org/openedx/core/domain/model/EnrolledCourseData.kt b/core/src/main/java/org/openedx/core/domain/model/EnrolledCourseData.kt index 2a66cccde..f7d5c0963 100644 --- a/core/src/main/java/org/openedx/core/domain/model/EnrolledCourseData.kt +++ b/core/src/main/java/org/openedx/core/domain/model/EnrolledCourseData.kt @@ -2,7 +2,8 @@ package org.openedx.core.domain.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -import java.util.* +import org.openedx.core.utils.TimeUtils +import java.util.Date @Parcelize data class EnrolledCourseData( @@ -14,7 +15,7 @@ data class EnrolledCourseData( val startDisplay: String, val startType: String, val end: Date?, - val dynamicUpgradeDeadline: String, + val upgradeDeadline: String, val subscriptionId: String, val coursewareAccess: CoursewareAccess?, val media: Media?, @@ -26,4 +27,10 @@ data class EnrolledCourseData( val discussionUrl: String, val videoOutline: String, val isSelfPaced: Boolean -) : Parcelable \ No newline at end of file +) : Parcelable { + val isStarted: Boolean + get() = TimeUtils.isDatePassed(Date(), start) + + val isUpgradeDeadlinePassed: Boolean + get() = TimeUtils.isDatePassed(Date(), TimeUtils.iso8601ToDate(upgradeDeadline)) +} diff --git a/core/src/main/java/org/openedx/core/domain/model/EnrollmentDetails.kt b/core/src/main/java/org/openedx/core/domain/model/EnrollmentDetails.kt new file mode 100644 index 000000000..1bd89d4ef --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/EnrollmentDetails.kt @@ -0,0 +1,20 @@ +package org.openedx.core.domain.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize +import org.openedx.core.utils.TimeUtils +import java.util.Date + +@Parcelize +data class EnrollmentDetails( + var created: Date?, + var mode: String?, + var isActive: Boolean, + var upgradeDeadline: Date?, +) : Parcelable { + val isUpgradeDeadlinePassed: Boolean + get() = TimeUtils.isDatePassed(Date(), upgradeDeadline) + + val isAuditMode: Boolean + get() = EnrollmentMode.AUDIT.toString().equals(mode, ignoreCase = true) +} diff --git a/core/src/main/java/org/openedx/core/domain/model/EnrollmentMode.kt b/core/src/main/java/org/openedx/core/domain/model/EnrollmentMode.kt new file mode 100644 index 000000000..08df4208b --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/EnrollmentMode.kt @@ -0,0 +1,14 @@ +package org.openedx.core.domain.model + +/** + * Course Enrollment modes + */ +enum class EnrollmentMode(private val mode: String) { + AUDIT("audit"), + VERIFIED("verified"), + NONE("none"); + + override fun toString(): String { + return mode + } +} diff --git a/core/src/main/java/org/openedx/core/domain/model/iap/AddToBasketResponse.kt b/core/src/main/java/org/openedx/core/domain/model/iap/AddToBasketResponse.kt new file mode 100644 index 000000000..391375702 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/iap/AddToBasketResponse.kt @@ -0,0 +1,3 @@ +package org.openedx.core.domain.model.iap + +data class AddToBasketResponse(val basketId: Long) diff --git a/core/src/main/java/org/openedx/core/domain/model/iap/CheckoutResponse.kt b/core/src/main/java/org/openedx/core/domain/model/iap/CheckoutResponse.kt new file mode 100644 index 000000000..7fc893420 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/iap/CheckoutResponse.kt @@ -0,0 +1,3 @@ +package org.openedx.core.domain.model.iap + +object CheckoutResponse diff --git a/core/src/main/java/org/openedx/core/domain/model/iap/ExecuteOrderResponse.kt b/core/src/main/java/org/openedx/core/domain/model/iap/ExecuteOrderResponse.kt new file mode 100644 index 000000000..1f18d327c --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/iap/ExecuteOrderResponse.kt @@ -0,0 +1,3 @@ +package org.openedx.core.domain.model.iap + +data object ExecuteOrderResponse diff --git a/core/src/main/java/org/openedx/core/domain/model/iap/ProductInfo.kt b/core/src/main/java/org/openedx/core/domain/model/iap/ProductInfo.kt new file mode 100644 index 000000000..b9e5da3d4 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/iap/ProductInfo.kt @@ -0,0 +1,10 @@ +package org.openedx.core.domain.model.iap + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class ProductInfo( + val courseSku: String, + val storeSku: String, +) : Parcelable diff --git a/core/src/main/java/org/openedx/core/domain/model/iap/PurchaseFlowData.kt b/core/src/main/java/org/openedx/core/domain/model/iap/PurchaseFlowData.kt new file mode 100644 index 000000000..1102e2348 --- /dev/null +++ b/core/src/main/java/org/openedx/core/domain/model/iap/PurchaseFlowData.kt @@ -0,0 +1,38 @@ +package org.openedx.core.domain.model.iap + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class PurchaseFlowData( + var screenName: String? = null, + var courseId: String? = null, + var courseName: String? = null, + var isSelfPaced: Boolean? = null, + var componentId: String? = null, + var productInfo: ProductInfo? = null, +) : Parcelable { + + var currencyCode: String = "" + var price: Double = 0.0 + var formattedPrice: String? = null + var purchaseToken: String? = null + var basketId: Long = -1 + + var flowStartTime: Long = 0 + + fun reset() { + screenName = null + courseId = null + courseName = null + isSelfPaced = null + componentId = null + productInfo = null + currencyCode = "" + price = 0.0 + formattedPrice = null + purchaseToken = null + basketId = -1 + flowStartTime = 0 + } +} diff --git a/core/src/main/java/org/openedx/core/exception/iap/IAPException.kt b/core/src/main/java/org/openedx/core/exception/iap/IAPException.kt new file mode 100644 index 000000000..45a6fd4d6 --- /dev/null +++ b/core/src/main/java/org/openedx/core/exception/iap/IAPException.kt @@ -0,0 +1,160 @@ +package org.openedx.core.exception.iap + +import android.text.TextUtils +import com.android.billingclient.api.BillingClient +import org.json.JSONObject +import org.openedx.core.presentation.iap.IAPErrorDialogType +import org.openedx.core.presentation.iap.IAPRequestType +import retrofit2.Response +import java.util.Locale + +/** + * + * Signals that the user unable to complete the in-app purchases follow it being not parsable or + * incomplete according to what we expect. + * + * @param requestType stores the request type for exception occurs. + * @param httpErrorCode stores the error codes can be either [BillingClient][com.android.billingclient.api.BillingClient] + * OR http error codes for ecommerce end-points, and setting it up to `-1` + * cause some at some service return error code `0`. + * @param errorMessage stores the error messages received from BillingClient & ecommerce end-points. + * */ +class IAPException( + val requestType: IAPRequestType = IAPRequestType.UNKNOWN, + val httpErrorCode: Int = DEFAULT_HTTP_ERROR_CODE, + val errorMessage: String +) : Exception(errorMessage) { + + /** + * Returns a StringBuilder containing the formatted error message. + * i.e Error: error_endpoint-error_code-error_message + * + * @return Formatted error message. + */ + fun getFormattedErrorMessage(): String { + val body = StringBuilder() + if (requestType == IAPRequestType.UNKNOWN) { + return body.toString() + } + body.append(String.format("%s", requestType.request)) + // change the default value to -1 cuz in case of BillingClient return errorCode 0 for price load. + if (httpErrorCode == DEFAULT_HTTP_ERROR_CODE) { + return body.toString() + } + body.append(String.format(Locale.ENGLISH, "-%d", httpErrorCode)) + if (!TextUtils.isEmpty(errorMessage)) body.append(String.format("-%s", errorMessage)) + return body.toString() + } + + fun getIAPErrorDialogType(): IAPErrorDialogType { + return when (requestType) { + IAPRequestType.PRICE_CODE -> { + IAPErrorDialogType.PRICE_ERROR_DIALOG + } + + IAPRequestType.NO_SKU_CODE -> { + IAPErrorDialogType.NO_SKU_ERROR_DIALOG + } + + IAPRequestType.ADD_TO_BASKET_CODE -> { + when (httpErrorCode) { + 400 -> { + IAPErrorDialogType.ADD_TO_BASKET_BAD_REQUEST_ERROR_DIALOG + } + + 403 -> { + IAPErrorDialogType.ADD_TO_BASKET_FORBIDDEN_ERROR_DIALOG + } + + 406 -> { + IAPErrorDialogType.ADD_TO_BASKET_NOT_ACCEPTABLE_ERROR_DIALOG + } + + else -> { + IAPErrorDialogType.ADD_TO_BASKET_GENERAL_ERROR_DIALOG + } + } + } + + IAPRequestType.CHECKOUT_CODE -> { + when (httpErrorCode) { + 400 -> { + IAPErrorDialogType.CHECKOUT_BAD_REQUEST_ERROR_DIALOG + } + + 403 -> { + IAPErrorDialogType.CHECKOUT_FORBIDDEN_ERROR_DIALOG + } + + 406 -> { + IAPErrorDialogType.CHECKOUT_NOT_ACCEPTABLE_ERROR_DIALOG + } + + else -> { + IAPErrorDialogType.CHECKOUT_GENERAL_ERROR_DIALOG + } + + } + } + + IAPRequestType.EXECUTE_ORDER_CODE -> { + when (httpErrorCode) { + 400 -> { + IAPErrorDialogType.EXECUTE_BAD_REQUEST_ERROR_DIALOG + } + + 403 -> { + IAPErrorDialogType.EXECUTE_FORBIDDEN_ERROR_DIALOG + } + + 406 -> { + IAPErrorDialogType.EXECUTE_NOT_ACCEPTABLE_ERROR_DIALOG + } + + 409 -> { + IAPErrorDialogType.EXECUTE_CONFLICT_ERROR_DIALOG + } + + else -> { + IAPErrorDialogType.EXECUTE_GENERAL_ERROR_DIALOG + } + } + } + + IAPRequestType.CONSUME_CODE -> { + IAPErrorDialogType.CONSUME_ERROR_DIALOG + } + + IAPRequestType.PAYMENT_SDK_CODE -> { + if (httpErrorCode == BillingClient.BillingResponseCode.BILLING_UNAVAILABLE) { + IAPErrorDialogType.PAYMENT_SDK_ERROR_DIALOG + } else { + IAPErrorDialogType.GENERAL_DIALOG_ERROR + } + } + + else -> { + IAPErrorDialogType.GENERAL_DIALOG_ERROR + } + } + } + + companion object { + private const val DEFAULT_HTTP_ERROR_CODE = -1 + } +} + +/** + * Attempts to extract error message from api responses and fails gracefully if unable to do so. + * + * @return extracted text message; null if no message was received or was unable to parse it. + */ +fun Response.getMessage(): String { + if (isSuccessful) return message() + return try { + val errors = JSONObject(errorBody()?.string() ?: "{}") + errors.optString("error") + } catch (ex: Exception) { + "" + } +} diff --git a/core/src/main/java/org/openedx/core/extension/EncryptionExt.kt b/core/src/main/java/org/openedx/core/extension/EncryptionExt.kt new file mode 100644 index 000000000..5b00d6a7f --- /dev/null +++ b/core/src/main/java/org/openedx/core/extension/EncryptionExt.kt @@ -0,0 +1,27 @@ +package org.openedx.core.extension + +import android.util.Base64 + +fun Long.encodeToString(): String { + return Base64.encodeToString(this.toString().toByteArray(), Base64.DEFAULT) +} + +fun String.encodeToString(): String { + return Base64.encodeToString(this.toByteArray(), Base64.DEFAULT) +} + +fun String.decodeToLong(): Long? { + return try { + Base64.decode(this, Base64.DEFAULT).toString(Charsets.UTF_8).toLong() + } catch (ex: Exception) { + null + } +} + +fun String.decodeToString(): String? { + return try { + Base64.decode(this, Base64.DEFAULT).toString(Charsets.UTF_8) + } catch (ex: Exception) { + null + } +} diff --git a/core/src/main/java/org/openedx/core/extension/ViewExt.kt b/core/src/main/java/org/openedx/core/extension/ViewExt.kt index ebd007d3d..12155a2b7 100644 --- a/core/src/main/java/org/openedx/core/extension/ViewExt.kt +++ b/core/src/main/java/org/openedx/core/extension/ViewExt.kt @@ -50,6 +50,15 @@ fun DialogFragment.setWidthPercent(percentage: Int) { dialog?.window?.setLayout(percentWidth.toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) } +fun DialogFragment.setFullScreen(percentage: Int) { + val percent = percentage.toFloat() / 100 + val dm = Resources.getSystem().displayMetrics + val rect = dm.run { Rect(0, 0, widthPixels, heightPixels) } + val percentWidth = rect.width() * percent + val percentHeight = rect.height() * percent + dialog?.window?.setLayout(percentWidth.toInt(), percentHeight.toInt()) +} + fun Context.toastMessage(message: String) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show() } diff --git a/core/src/main/java/org/openedx/core/module/billing/BillingProcessor.kt b/core/src/main/java/org/openedx/core/module/billing/BillingProcessor.kt new file mode 100644 index 000000000..dff7a717c --- /dev/null +++ b/core/src/main/java/org/openedx/core/module/billing/BillingProcessor.kt @@ -0,0 +1,205 @@ +package org.openedx.core.module.billing + +import android.app.Activity +import android.content.Context +import com.android.billingclient.api.AcknowledgePurchaseParams +import com.android.billingclient.api.BillingClient +import com.android.billingclient.api.BillingClientStateListener +import com.android.billingclient.api.BillingFlowParams +import com.android.billingclient.api.BillingResult +import com.android.billingclient.api.ConsumeParams +import com.android.billingclient.api.ProductDetails +import com.android.billingclient.api.ProductDetailsResult +import com.android.billingclient.api.Purchase +import com.android.billingclient.api.PurchasesUpdatedListener +import com.android.billingclient.api.QueryProductDetailsParams +import com.android.billingclient.api.QueryPurchasesParams +import com.android.billingclient.api.acknowledgePurchase +import com.android.billingclient.api.consumePurchase +import com.android.billingclient.api.queryProductDetails +import com.android.billingclient.api.queryPurchasesAsync +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext +import org.openedx.core.domain.model.iap.ProductInfo +import org.openedx.core.extension.decodeToString +import org.openedx.core.extension.encodeToString +import org.openedx.core.extension.safeResume +import org.openedx.core.utils.Logger + +class BillingProcessor( + context: Context, + private val dispatcher: CoroutineDispatcher, +) : PurchasesUpdatedListener { + + private val logger = Logger(TAG) + + private var listener: PurchaseListeners? = null + + private var billingClient = BillingClient.newBuilder(context) + .setListener(this) + .enablePendingPurchases() + .build() + + override fun onPurchasesUpdated( + billingResult: BillingResult, + purchases: MutableList? + ) { + if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) { + if (!purchases.first().isAcknowledged) { + CoroutineScope(dispatcher).launch { + acknowledgePurchase(purchases.first()) + } + } else { + listener?.onPurchaseComplete(purchases.first()) + } + } else { + listener?.onPurchaseCancel(billingResult.responseCode, billingResult.debugMessage) + } + } + + fun setPurchaseListener(listener: PurchaseListeners) { + this.listener = listener + } + + private suspend fun isReadyOrConnect(): Boolean { + return billingClient.isReady || connect() + } + + private suspend fun connect(): Boolean { + return suspendCancellableCoroutine { continuation -> + val billingClientStateListener = object : BillingClientStateListener { + override fun onBillingSetupFinished(billingResult: BillingResult) { + logger.d { "BillingSetupFinished -> $billingResult" } + if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { + continuation.safeResume(true) { + continuation.cancel() + } + } else { + continuation.safeResume(false) { + continuation.cancel() + } + } + } + + override fun onBillingServiceDisconnected() { + continuation.safeResume(false) { + continuation.cancel() + } + } + } + billingClient.startConnection(billingClientStateListener) + } + } + + suspend fun querySyncDetails(productId: String): ProductDetailsResult { + isReadyOrConnect() + val productDetails = QueryProductDetailsParams.Product.newBuilder() + .setProductId(productId) + .setProductType(BillingClient.ProductType.INAPP) + .build() + + return withContext(dispatcher) { + billingClient.queryProductDetails( + QueryProductDetailsParams + .newBuilder() + .setProductList(listOf(productDetails)) + .build() + ) + } + } + + suspend fun purchaseItem( + activity: Activity, + userId: Long, + productInfo: ProductInfo, + ) { + if (isReadyOrConnect()) { + val response = querySyncDetails(productInfo.storeSku) + + response.productDetailsList?.first()?.let { + launchBillingFlow(activity, it, userId, productInfo.courseSku) + } + } else { + listener?.onPurchaseCancel(BillingClient.BillingResponseCode.BILLING_UNAVAILABLE, "") + } + } + + private fun launchBillingFlow( + activity: Activity, + productDetails: ProductDetails, + userId: Long, + courseSku: String, + ) { + val productDetailsParamsList = listOf( + BillingFlowParams.ProductDetailsParams.newBuilder() + .setProductDetails(productDetails) + .build() + ) + + val billingFlowParams = BillingFlowParams.newBuilder() + .setProductDetailsParamsList(productDetailsParamsList) + .setObfuscatedAccountId(userId.encodeToString()) + .setObfuscatedProfileId(courseSku.encodeToString()) + .build() + + billingClient.launchBillingFlow(activity, billingFlowParams) + } + + private suspend fun acknowledgePurchase(purchase: Purchase) { + isReadyOrConnect() + val billingResult = billingClient.acknowledgePurchase( + AcknowledgePurchaseParams.newBuilder() + .setPurchaseToken(purchase.purchaseToken) + .build() + ) + if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { + listener?.onPurchaseComplete(purchase) + } + } + + suspend fun consumePurchase(purchaseToken: String): BillingResult { + isReadyOrConnect() + val result = billingClient.consumePurchase( + ConsumeParams + .newBuilder() + .setPurchaseToken(purchaseToken) + .build() + ) + return result.billingResult + } + + /** + * Method to query the Purchases async and returns purchases for currently owned items + * bought within the app. + * + * @return List of purchases + **/ + suspend fun queryPurchases(): List { + isReadyOrConnect() + return billingClient.queryPurchasesAsync( + QueryPurchasesParams.newBuilder() + .setProductType(BillingClient.ProductType.INAPP) + .build() + ).purchasesList.filter { it.purchaseState == Purchase.PurchaseState.PURCHASED } + } + + companion object { + private const val TAG = "BillingClientWrapper" + const val MICROS_TO_UNIT = 1_000_000 // 1,000,000 micro-units equal one unit of the currency + } + + interface PurchaseListeners { + fun onPurchaseComplete(purchase: Purchase) + fun onPurchaseCancel(responseCode: Int, message: String) + } +} + +fun ProductDetails.OneTimePurchaseOfferDetails.getPriceAmount(): Double = + this.priceAmountMicros.toDouble().div(BillingProcessor.MICROS_TO_UNIT) + +fun Purchase.getCourseSku(): String? { + return this.accountIdentifiers?.obfuscatedProfileId?.decodeToString() +} diff --git a/core/src/main/java/org/openedx/core/presentation/IAPAnalytics.kt b/core/src/main/java/org/openedx/core/presentation/IAPAnalytics.kt new file mode 100644 index 000000000..68bd4f7c2 --- /dev/null +++ b/core/src/main/java/org/openedx/core/presentation/IAPAnalytics.kt @@ -0,0 +1,70 @@ +package org.openedx.core.presentation + +interface IAPAnalytics { + fun logEvent(event: String, params: Map) +} + +enum class IAPAnalyticsEvent(val eventName: String, val biValue: String) { + // In App Purchases Events + IAP_UPGRADE_NOW_CLICKED( + "Payments: Upgrade Now Clicked", + "edx.bi.app.payments.upgrade_now.clicked" + ), + IAP_COURSE_UPGRADE_SUCCESS( + "Payments: Course Upgrade Success", + "edx.bi.app.payments.course_upgrade_success" + ), + IAP_PAYMENT_ERROR( + "Payments: Payment Error", + "edx.bi.app.payments.payment_error" + ), + IAP_PAYMENT_CANCELED( + "Payments: Canceled by User", + "edx.bi.app.payments.canceled_by_user" + ), + IAP_COURSE_UPGRADE_ERROR( + "Payments: Course Upgrade Error", + "edx.bi.app.payments.course_upgrade_error" + ), + IAP_PRICE_LOAD_ERROR( + "Payments: Price Load Error", + "edx.bi.app.payments.price_load_error" + ), + IAP_ERROR_ALERT_ACTION( + "Payments: Error Alert Action", + "edx.bi.app.payments.error_alert_action" + ), + IAP_UNFULFILLED_PURCHASE_INITIATED( + "Payments: Unfulfilled Purchase Initiated", + "edx.bi.app.payments.unfulfilled_purchase.initiated" + ), + IAP_RESTORE_PURCHASE_CLICKED( + "Payments: Restore Purchases Clicked", + "edx.bi.app.payments.restore_purchases.clicked" + ) +} + +enum class IAPAnalyticsKeys(val key: String) { + NAME("name"), + CATEGORY("category"), + IN_APP_PURCHASES("in_app_purchases"), + COURSE_ID("course_id"), + PACING("pacing"), + SELF("self"), + INSTRUCTOR("instructor"), + IAP_FLOW_TYPE("flow_type"), + PRICE("price"), + COMPONENT_ID("component_id"), + ELAPSED_TIME("elapsed_time"), + ERROR("error"), + ERROR_ACTION("error_action"), + ACTION("action"), + SCREEN_NAME("screen_name"), + ERROR_ALERT_TYPE("error_alert_type"), +} + +enum class IAPAnalyticsScreen(val screenName: String) { + COURSE_ENROLLMENT("course_enrollment"), + COURSE_DASHBOARD("course_dashboard"), + PROFILE("profile"), +} diff --git a/core/src/main/java/org/openedx/core/presentation/dialog/IAPDialogFragment.kt b/core/src/main/java/org/openedx/core/presentation/dialog/IAPDialogFragment.kt new file mode 100644 index 000000000..c18ce07b2 --- /dev/null +++ b/core/src/main/java/org/openedx/core/presentation/dialog/IAPDialogFragment.kt @@ -0,0 +1,273 @@ +package org.openedx.core.presentation.dialog + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment +import org.koin.androidx.viewmodel.ext.android.viewModel +import org.koin.core.parameter.parametersOf +import org.openedx.core.R +import org.openedx.core.domain.model.iap.ProductInfo +import org.openedx.core.domain.model.iap.PurchaseFlowData +import org.openedx.core.extension.parcelable +import org.openedx.core.extension.serializable +import org.openedx.core.extension.setFullScreen +import org.openedx.core.presentation.iap.IAPAction +import org.openedx.core.presentation.iap.IAPFlow +import org.openedx.core.presentation.iap.IAPLoaderType +import org.openedx.core.presentation.iap.IAPRequestType +import org.openedx.core.presentation.iap.IAPUIState +import org.openedx.core.presentation.iap.IAPViewModel +import org.openedx.core.ui.HandleUIMessage +import org.openedx.core.ui.IAPErrorDialog +import org.openedx.core.ui.OpenEdXButton +import org.openedx.core.ui.UnlockingAccessView +import org.openedx.core.ui.ValuePropUpgradeFeatures +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors + +class IAPDialogFragment : DialogFragment() { + + private val iapViewModel by viewModel { + parametersOf( + requireArguments().serializable(ARG_IAP_FLOW), + requireArguments().parcelable(ARG_PURCHASE_FLOW_DATA) + ) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ) = ComposeView(requireContext()).apply { + dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + OpenEdXTheme { + val iapState by iapViewModel.uiState.collectAsState() + val uiMessage by iapViewModel.uiMessage.collectAsState(null) + val scaffoldState = rememberScaffoldState() + + val isFullScreenLoader = + (iapState as? IAPUIState.Loading)?.loaderType == IAPLoaderType.FULL_SCREEN + + Scaffold( + modifier = Modifier.fillMaxSize(), + backgroundColor = MaterialTheme.appColors.background, + topBar = { + if (isFullScreenLoader.not()) { + Row( + modifier = Modifier.padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Spacer(Modifier.weight(1f)) + Icon( + modifier = Modifier.clickable { onDismiss() }, + imageVector = Icons.Filled.Close, + contentDescription = null + ) + } + } + }, + bottomBar = { + if (isFullScreenLoader.not()) { + Box(modifier = Modifier.padding(all = 16.dp)) { + when { + (iapState is IAPUIState.Loading || + iapState is IAPUIState.PurchaseProduct || + iapState is IAPUIState.Error) -> { + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.appColors.primary) + } + } + + iapState is IAPUIState.ProductData && + iapViewModel.purchaseData.formattedPrice.isNullOrEmpty() + .not() -> { + OpenEdXButton(modifier = Modifier.fillMaxWidth(), + text = stringResource( + id = R.string.iap_upgrade_price, + iapViewModel.purchaseData.formattedPrice!!, + ), + onClick = { + iapViewModel.startPurchaseFlow() + }) + } + } + } + } + } + ) { contentPadding -> + + HandleUIMessage( + uiMessage = uiMessage, + scaffoldState = scaffoldState, + onDisplayed = { + if (iapState is IAPUIState.CourseDataUpdated) { + onDismiss() + } + } + ) + + when (iapState) { + is IAPUIState.PurchaseProduct -> { + iapViewModel.purchaseItem(requireActivity()) + } + + is IAPUIState.Error -> { + val iapException = (iapState as IAPUIState.Error).iapException + IAPErrorDialog(iapException = iapException, onIAPAction = { iapAction -> + when (iapAction) { + IAPAction.ACTION_RELOAD_PRICE -> { + iapViewModel.logIAPErrorActionEvent( + iapException.requestType.request, + IAPAction.ACTION_RELOAD_PRICE.action + ) + iapViewModel.loadPrice() + } + + IAPAction.ACTION_CLOSE -> { + iapViewModel.logIAPErrorActionEvent( + iapException.requestType.request, + IAPAction.ACTION_CLOSE.action + ) + onDismiss() + } + + IAPAction.ACTION_OK -> { + iapViewModel.logIAPErrorActionEvent( + iapException.requestType.request, + IAPAction.ACTION_OK.action + ) + onDismiss() + } + + IAPAction.ACTION_REFRESH -> { + iapViewModel.logIAPErrorActionEvent( + iapException.requestType.request, + IAPAction.ACTION_REFRESH.action + ) + iapViewModel.refreshCourse() + } + + IAPAction.ACTION_GET_HELP -> { + iapViewModel.showFeedbackScreen( + requireActivity(), + iapException.requestType.request, + iapException.getFormattedErrorMessage() + ) + onDismiss() + } + + IAPAction.ACTION_RETRY -> { + iapViewModel.logIAPErrorActionEvent( + iapException.requestType.request, + IAPAction.ACTION_RETRY.action + ) + if (iapException.requestType == IAPRequestType.CONSUME_CODE) { + iapViewModel.retryToConsumeOrder() + } else if (iapException.requestType == IAPRequestType.EXECUTE_ORDER_CODE) { + iapViewModel.retryExecuteOrder() + } + } + + else -> { + // ignore + } + } + }) + } + + is IAPUIState.Clear -> { + onDismiss() + } + + else -> {} + } + + if (isFullScreenLoader) { + UnlockingAccessView() + } else if (TextUtils.isEmpty(iapViewModel.purchaseData.courseName).not()) { + ValuePropUpgradeFeatures( + Modifier.padding(contentPadding), + iapViewModel.purchaseData.courseName!! + ) + } + } + } + } + } + + override fun onStart() { + super.onStart() + setFullScreen(100) + } + + private fun onDismiss() { + iapViewModel.clearIAPFLow() + dismiss() + } + + companion object { + const val TAG = "IAPDialogFragment" + + private const val ARG_IAP_FLOW = "iap_flow" + private const val ARG_PURCHASE_FLOW_DATA = "purchase_flow_data" + + fun newInstance( + iapFlow: IAPFlow, + screenName: String = "", + courseId: String = "", + courseName: String = "", + isSelfPaced: Boolean = false, + componentId: String? = null, + productInfo: ProductInfo? = null + ): IAPDialogFragment { + val fragment = IAPDialogFragment() + val purchaseFlowData = PurchaseFlowData().apply { + this.screenName = screenName + this.courseId = courseId + this.courseName = courseName + this.isSelfPaced = isSelfPaced + this.componentId = componentId + this.productInfo = productInfo + } + + fragment.arguments = bundleOf( + ARG_IAP_FLOW to iapFlow, + ARG_PURCHASE_FLOW_DATA to purchaseFlowData + ) + return fragment + } + } +} diff --git a/core/src/main/java/org/openedx/core/presentation/iap/IAPErrorDialogType.kt b/core/src/main/java/org/openedx/core/presentation/iap/IAPErrorDialogType.kt new file mode 100644 index 000000000..079d5736e --- /dev/null +++ b/core/src/main/java/org/openedx/core/presentation/iap/IAPErrorDialogType.kt @@ -0,0 +1,110 @@ +package org.openedx.core.presentation.iap + +import org.openedx.core.R + +/** + * 400 - BAD_REQUEST + * 403 - FORBIDDEN + * 406 - NOT_ACCEPTABLE + * 409 - CONFLICT + * General - GENERAL + * */ +enum class IAPErrorDialogType( + val messageResId: Int = 0, + val positiveButtonResId: Int = 0, + val negativeButtonResId: Int = 0, + val neutralButtonResId: Int = 0, +) { + PRICE_ERROR_DIALOG( + R.string.iap_error_price_not_fetched, + R.string.core_error_try_again, + R.string.core_cancel + ), + NO_SKU_ERROR_DIALOG, + ADD_TO_BASKET_BAD_REQUEST_ERROR_DIALOG( + R.string.iap_course_not_available_message, + R.string.core_cancel, + R.string.iap_get_help + ), + ADD_TO_BASKET_FORBIDDEN_ERROR_DIALOG( + R.string.iap_unauthenticated_account_message, + R.string.core_cancel, + R.string.iap_get_help + ), + ADD_TO_BASKET_NOT_ACCEPTABLE_ERROR_DIALOG( + R.string.iap_course_already_paid_for_message, + R.string.iap_label_refresh_now, + R.string.core_cancel + ), + ADD_TO_BASKET_GENERAL_ERROR_DIALOG( + R.string.iap_general_upgrade_error_message, + R.string.core_cancel, + R.string.iap_get_help + ), + CHECKOUT_BAD_REQUEST_ERROR_DIALOG( + R.string.iap_payment_could_not_be_processed, + R.string.core_cancel, + R.string.iap_get_help + ), + CHECKOUT_FORBIDDEN_ERROR_DIALOG( + R.string.iap_unauthenticated_account_message, + R.string.core_cancel, + R.string.iap_get_help + ), + CHECKOUT_NOT_ACCEPTABLE_ERROR_DIALOG( + R.string.iap_course_not_available_message, + R.string.iap_label_refresh_now, + R.string.core_cancel + ), + CHECKOUT_GENERAL_ERROR_DIALOG( + R.string.iap_general_upgrade_error_message, + R.string.core_cancel, + R.string.iap_get_help + ), + EXECUTE_BAD_REQUEST_ERROR_DIALOG( + R.string.iap_course_not_fullfilled, + R.string.iap_refresh_to_retry, + R.string.iap_get_help, + R.string.core_cancel + ), + EXECUTE_FORBIDDEN_ERROR_DIALOG( + R.string.iap_course_not_fullfilled, + R.string.iap_refresh_to_retry, + R.string.iap_get_help, + R.string.core_cancel + ), + EXECUTE_NOT_ACCEPTABLE_ERROR_DIALOG( + R.string.iap_course_already_paid_for_message, + R.string.iap_label_refresh_now, + R.string.iap_get_help, + R.string.core_cancel + ), + EXECUTE_CONFLICT_ERROR_DIALOG( + R.string.iap_course_already_paid_for_message, + R.string.core_cancel, + R.string.iap_get_help + ), + EXECUTE_GENERAL_ERROR_DIALOG( + R.string.iap_general_upgrade_error_message, + R.string.iap_refresh_to_retry, + R.string.iap_get_help, + R.string.core_cancel + ), + CONSUME_ERROR_DIALOG( + R.string.iap_course_not_fullfilled, + R.string.iap_refresh_to_retry, + R.string.iap_get_help, + R.string.core_cancel + ), + PAYMENT_SDK_ERROR_DIALOG( + R.string.iap_payment_could_not_be_processed, + R.string.core_cancel, + R.string.iap_get_help + ), + GENERAL_DIALOG_ERROR( + R.string.iap_general_upgrade_error_message, + R.string.core_cancel, + R.string.iap_get_help + ), + NONE; +} diff --git a/core/src/main/java/org/openedx/core/presentation/iap/IAPUIState.kt b/core/src/main/java/org/openedx/core/presentation/iap/IAPUIState.kt new file mode 100644 index 000000000..95bced19f --- /dev/null +++ b/core/src/main/java/org/openedx/core/presentation/iap/IAPUIState.kt @@ -0,0 +1,61 @@ +package org.openedx.core.presentation.iap + +import org.openedx.core.exception.iap.IAPException + +sealed class IAPUIState { + data class ProductData(val formattedPrice: String) : IAPUIState() + data object PurchaseProduct : IAPUIState() + data object PurchasesFulfillmentCompleted : IAPUIState() + data object FakePurchasesFulfillmentCompleted : IAPUIState() + data object CourseDataUpdated : IAPUIState() + data class Loading(val loaderType: IAPLoaderType) : IAPUIState() + data class Error(val iapException: IAPException) : IAPUIState() + data object Clear : IAPUIState() +} + +enum class IAPLoaderType { + PRICE, PURCHASE_FLOW, FULL_SCREEN, RESTORE_PURCHASES +} + +enum class IAPFlow(val value: String) { + RESTORE("restore"), + SILENT("silent"), + USER_INITIATED("user_initiated"); + + fun value(): String { + return this.name.lowercase() + } +} + +enum class IAPAction(val action: String) { + ACTION_USER_INITIATED("user_initiated"), + ACTION_GET_HELP("get_help"), + ACTION_CLOSE("close"), + ACTION_RELOAD_PRICE("reload_price"), + ACTION_REFRESH("refresh"), + ACTION_RETRY("retry"), + ACTION_UNFULFILLED("unfulfilled"), + ACTION_RESTORE("restore"), + ACTION_ERROR_CLOSE("error_close"), + ACTION_COMPLETION("completion"), + ACTION_OK("ok"), + ACTION_RESTORE_PURCHASE_CANCEL("restore_purchase_cancel") +} + +enum class IAPRequestType(val request: String) { + // Custom Codes for request types + PRICE_CODE("price_fetch"), + ADD_TO_BASKET_CODE("basket"), + CHECKOUT_CODE("checkout"), + PAYMENT_SDK_CODE("payment"), + EXECUTE_ORDER_CODE("execute"), + NO_SKU_CODE("sku"), + CONSUME_CODE("consume"), + UNFULFILLED_CODE("unfulfilled"), + RESTORE_CODE("restore"), + UNKNOWN("unknown"); + + override fun toString(): String { + return request + } +} diff --git a/core/src/main/java/org/openedx/core/presentation/iap/IAPViewModel.kt b/core/src/main/java/org/openedx/core/presentation/iap/IAPViewModel.kt new file mode 100644 index 000000000..2946ef5df --- /dev/null +++ b/core/src/main/java/org/openedx/core/presentation/iap/IAPViewModel.kt @@ -0,0 +1,366 @@ +package org.openedx.core.presentation.iap + +import android.content.Context +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.viewModelScope +import com.android.billingclient.api.BillingClient +import com.android.billingclient.api.Purchase +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import org.openedx.core.BaseViewModel +import org.openedx.core.R +import org.openedx.core.UIMessage +import org.openedx.core.config.Config +import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.interactor.IAPInteractor +import org.openedx.core.domain.model.iap.PurchaseFlowData +import org.openedx.core.exception.iap.IAPException +import org.openedx.core.module.billing.BillingProcessor +import org.openedx.core.module.billing.getCourseSku +import org.openedx.core.module.billing.getPriceAmount +import org.openedx.core.presentation.IAPAnalytics +import org.openedx.core.presentation.IAPAnalyticsEvent +import org.openedx.core.presentation.IAPAnalyticsKeys +import org.openedx.core.presentation.global.AppData +import org.openedx.core.system.ResourceManager +import org.openedx.core.system.notifier.CourseDataUpdated +import org.openedx.core.system.notifier.IAPNotifier +import org.openedx.core.system.notifier.UpdateCourseData +import org.openedx.core.utils.EmailUtil +import org.openedx.core.utils.TimeUtils + +class IAPViewModel( + iapFlow: IAPFlow, + private val purchaseFlowData: PurchaseFlowData, + private val appData: AppData, + private val iapInteractor: IAPInteractor, + private val corePreferences: CorePreferences, + private val analytics: IAPAnalytics, + private val resourceManager: ResourceManager, + private val config: Config, + private val iapNotifier: IAPNotifier +) : BaseViewModel() { + + private val _uiState = MutableStateFlow(IAPUIState.Loading(IAPLoaderType.PRICE)) + val uiState: StateFlow + get() = _uiState.asStateFlow() + + private val _uiMessage = MutableSharedFlow() + val uiMessage: SharedFlow + get() = _uiMessage.asSharedFlow() + + val purchaseData: PurchaseFlowData + get() = purchaseFlowData + + private val purchaseListeners = object : BillingProcessor.PurchaseListeners { + override fun onPurchaseComplete(purchase: Purchase) { + if (purchase.getCourseSku() == purchaseFlowData.productInfo?.courseSku) { + _uiState.value = + IAPUIState.Loading(loaderType = IAPLoaderType.FULL_SCREEN) + purchaseFlowData.purchaseToken = purchase.purchaseToken + executeOrder(purchaseFlowData) + } + } + + override fun onPurchaseCancel(responseCode: Int, message: String) { + updateErrorState( + IAPException( + IAPRequestType.PAYMENT_SDK_CODE, + httpErrorCode = responseCode, + errorMessage = message + ) + ) + } + } + + init { + viewModelScope.launch(Dispatchers.IO) { + iapNotifier.notifier.onEach { event -> + when (event) { + is CourseDataUpdated -> { + upgradeSuccessEvent() + _uiMessage.emit(UIMessage.ToastMessage(resourceManager.getString(R.string.iap_success_message))) + _uiState.value = IAPUIState.CourseDataUpdated + } + } + }.distinctUntilChanged().launchIn(viewModelScope) + } + + when (iapFlow) { + IAPFlow.USER_INITIATED -> { + loadPrice() + } + + IAPFlow.SILENT, IAPFlow.RESTORE -> { + _uiState.value = IAPUIState.Loading(IAPLoaderType.FULL_SCREEN) + purchaseFlowData.flowStartTime = TimeUtils.getCurrentTime() + updateCourseData() + } + } + } + + fun loadPrice() { + viewModelScope.launch(Dispatchers.IO) { + purchaseFlowData.takeIf { it.courseId != null && it.productInfo != null } + ?.apply { + _uiState.value = IAPUIState.Loading(loaderType = IAPLoaderType.PRICE) + runCatching { + iapInteractor.loadPrice(purchaseFlowData.productInfo?.storeSku!!) + }.onSuccess { + this.formattedPrice = it.formattedPrice + this.price = it.getPriceAmount() + this.currencyCode = it.priceCurrencyCode + _uiState.value = + IAPUIState.ProductData(formattedPrice = this.formattedPrice!!) + }.onFailure { + if (it is IAPException) { + updateErrorState(it) + } + } + } ?: run { + updateErrorState( + IAPException( + requestType = IAPRequestType.PRICE_CODE, + httpErrorCode = IAPRequestType.PRICE_CODE.hashCode(), + errorMessage = "Product SKU is not provided in the request." + ) + ) + } + } + } + + fun startPurchaseFlow() { + upgradeNowClickedEvent() + _uiState.value = IAPUIState.Loading(loaderType = IAPLoaderType.PURCHASE_FLOW) + purchaseFlowData.flowStartTime = TimeUtils.getCurrentTime() + purchaseFlowData.takeIf { purchaseFlowData.courseName != null && it.productInfo != null } + ?.apply { + addToBasket(productInfo?.courseSku!!) + } ?: run { + updateErrorState( + IAPException( + requestType = IAPRequestType.NO_SKU_CODE, + httpErrorCode = IAPRequestType.NO_SKU_CODE.hashCode(), + errorMessage = "" + ) + ) + } + } + + private fun addToBasket(courseSku: String) { + viewModelScope.launch(Dispatchers.IO) { + runCatching { + iapInteractor.addToBasket(courseSku) + }.onSuccess { basketId -> + purchaseFlowData.basketId = basketId + processCheckout(basketId) + }.onFailure { + if (it is IAPException) { + updateErrorState(it) + } + } + } + } + + private fun processCheckout(basketId: Long) { + viewModelScope.launch(Dispatchers.IO) { + runCatching { + iapInteractor.processCheckout(basketId) + }.onSuccess { + _uiState.value = IAPUIState.PurchaseProduct + }.onFailure { + if (it is IAPException) { + updateErrorState(it) + } + } + } + } + + fun purchaseItem(activity: FragmentActivity) { + viewModelScope.launch(Dispatchers.IO) { + takeIf { + corePreferences.user?.id != null && purchaseFlowData.productInfo != null + }?.apply { + iapInteractor.purchaseItem( + activity, + corePreferences.user?.id!!, + purchaseFlowData.productInfo!!, + purchaseListeners + ) + } + } + } + + private fun executeOrder(purchaseFlowData: PurchaseFlowData) { + viewModelScope.launch(Dispatchers.IO) { + runCatching { + iapInteractor.executeOrder( + basketId = purchaseFlowData.basketId, + purchaseToken = purchaseFlowData.purchaseToken!!, + price = purchaseFlowData.price, + currencyCode = purchaseFlowData.currencyCode, + ) + }.onSuccess { + consumeOrderForFurtherPurchases(purchaseFlowData) + }.onFailure { + if (it is IAPException) { + updateErrorState(it) + } + } + } + } + + private fun consumeOrderForFurtherPurchases(purchaseFlowData: PurchaseFlowData) { + viewModelScope.launch(Dispatchers.IO) { + purchaseFlowData.purchaseToken?.let { + runCatching { + iapInteractor.consumePurchase(it) + }.onSuccess { + updateCourseData() + }.onFailure { + if (it is IAPException) { + updateErrorState(it) + } + } + } + } + } + + fun refreshCourse() { + _uiState.value = IAPUIState.Loading(IAPLoaderType.FULL_SCREEN) + purchaseFlowData.flowStartTime = TimeUtils.getCurrentTime() + updateCourseData() + } + + fun retryExecuteOrder() { + executeOrder(purchaseFlowData) + } + + fun retryToConsumeOrder() { + consumeOrderForFurtherPurchases(purchaseFlowData) + } + + private fun updateCourseData() { + viewModelScope.launch(Dispatchers.IO) { + purchaseFlowData.courseId?.let { courseId -> + iapNotifier.send(UpdateCourseData(courseId)) + } + } + } + + fun showFeedbackScreen(context: Context, flowType: String, message: String) { + EmailUtil.showFeedbackScreen( + context = context, + feedbackEmailAddress = config.getFeedbackEmailAddress(), + subject = context.getString(R.string.core_error_upgrading_course_in_app), + feedback = message, + appVersion = appData.versionName + ) + logIAPErrorActionEvent(flowType, IAPAction.ACTION_GET_HELP.action) + } + + private fun updateErrorState(iapException: IAPException) { + val feedbackErrorMessage: String = iapException.getFormattedErrorMessage() + when (iapException.requestType) { + IAPRequestType.PAYMENT_SDK_CODE -> { + if (BillingClient.BillingResponseCode.USER_CANCELED == iapException.httpErrorCode) { + canceledByUserEvent() + } else { + purchaseErrorEvent(feedbackErrorMessage) + } + } + + IAPRequestType.PRICE_CODE, + IAPRequestType.NO_SKU_CODE -> { + priceLoadErrorEvent(feedbackErrorMessage) + } + + else -> { + courseUpgradeErrorEvent(feedbackErrorMessage) + } + } + if (BillingClient.BillingResponseCode.USER_CANCELED != iapException.httpErrorCode) { + _uiState.value = IAPUIState.Error(iapException) + } else { + _uiState.value = IAPUIState.Clear + } + } + + private fun upgradeNowClickedEvent() { + logIAPEvent(IAPAnalyticsEvent.IAP_UPGRADE_NOW_CLICKED) + } + + private fun upgradeSuccessEvent() { + val elapsedTime = TimeUtils.getCurrentTime() - purchaseFlowData.flowStartTime + logIAPEvent(IAPAnalyticsEvent.IAP_COURSE_UPGRADE_SUCCESS, buildMap { + put(IAPAnalyticsKeys.ELAPSED_TIME.key, elapsedTime) + }.toMutableMap()) + } + + private fun purchaseErrorEvent(error: String) { + logIAPEvent(IAPAnalyticsEvent.IAP_PAYMENT_ERROR, buildMap { + put(IAPAnalyticsKeys.ERROR.key, error) + }.toMutableMap()) + } + + private fun canceledByUserEvent() { + logIAPEvent(IAPAnalyticsEvent.IAP_PAYMENT_CANCELED) + } + + private fun courseUpgradeErrorEvent(error: String) { + logIAPEvent(IAPAnalyticsEvent.IAP_COURSE_UPGRADE_ERROR, buildMap { + put(IAPAnalyticsKeys.ERROR.key, error) + }.toMutableMap()) + } + + private fun priceLoadErrorEvent(error: String) { + logIAPEvent(IAPAnalyticsEvent.IAP_PRICE_LOAD_ERROR, buildMap { + put(IAPAnalyticsKeys.ERROR.key, error) + }.toMutableMap()) + } + + fun logIAPErrorActionEvent(alertType: String, action: String) { + logIAPEvent(IAPAnalyticsEvent.IAP_ERROR_ALERT_ACTION, buildMap { + put(IAPAnalyticsKeys.ERROR_ALERT_TYPE.key, alertType) + put(IAPAnalyticsKeys.ERROR_ACTION.key, action) + }.toMutableMap()) + } + + private fun logIAPEvent( + event: IAPAnalyticsEvent, + params: MutableMap = mutableMapOf() + ) { + analytics.logEvent(event.eventName, params.apply { + put(IAPAnalyticsKeys.NAME.key, event.biValue) + purchaseFlowData.takeIf { it.courseId.isNullOrBlank().not() }?.let { + put(IAPAnalyticsKeys.COURSE_ID.key, purchaseFlowData.courseId) + put( + IAPAnalyticsKeys.PACING.key, + if (purchaseFlowData.isSelfPaced == true) IAPAnalyticsKeys.SELF.key else IAPAnalyticsKeys.INSTRUCTOR.key + ) + } + purchaseFlowData.formattedPrice?.takeIf { it.isNotBlank() }?.let { formattedPrice -> + put(IAPAnalyticsKeys.PRICE.key, formattedPrice) + } + purchaseFlowData.componentId?.takeIf { it.isNotBlank() }?.let { componentId -> + put(IAPAnalyticsKeys.COMPONENT_ID.key, componentId) + } + put(IAPAnalyticsKeys.SCREEN_NAME.key, purchaseFlowData.screenName) + put(IAPAnalyticsKeys.CATEGORY.key, IAPAnalyticsKeys.IN_APP_PURCHASES.key) + }) + } + + fun clearIAPFLow() { + _uiState.value = IAPUIState.Clear + purchaseFlowData.reset() + } +} diff --git a/core/src/main/java/org/openedx/core/system/notifier/CourseDataUpdated.kt b/core/src/main/java/org/openedx/core/system/notifier/CourseDataUpdated.kt new file mode 100644 index 000000000..e4ab84317 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/CourseDataUpdated.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier + +class CourseDataUpdated : IAPEvent diff --git a/core/src/main/java/org/openedx/core/system/notifier/IAPEvent.kt b/core/src/main/java/org/openedx/core/system/notifier/IAPEvent.kt new file mode 100644 index 000000000..52785ef36 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/IAPEvent.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier + +interface IAPEvent diff --git a/core/src/main/java/org/openedx/core/system/notifier/IAPNotifier.kt b/core/src/main/java/org/openedx/core/system/notifier/IAPNotifier.kt new file mode 100644 index 000000000..d32df0b5d --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/IAPNotifier.kt @@ -0,0 +1,14 @@ +package org.openedx.core.system.notifier + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow + +class IAPNotifier { + private val channel = MutableSharedFlow(replay = 0, extraBufferCapacity = 0) + + val notifier: Flow = channel.asSharedFlow() + suspend fun send(event: UpdateCourseData) = channel.emit(event) + + suspend fun send(event: CourseDataUpdated) = channel.emit(event) +} diff --git a/core/src/main/java/org/openedx/core/system/notifier/UpdateCourseData.kt b/core/src/main/java/org/openedx/core/system/notifier/UpdateCourseData.kt new file mode 100644 index 000000000..3ea3a19b1 --- /dev/null +++ b/core/src/main/java/org/openedx/core/system/notifier/UpdateCourseData.kt @@ -0,0 +1,3 @@ +package org.openedx.core.system.notifier + +data class UpdateCourseData(val courseId: String) : IAPEvent diff --git a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt index 26806897f..735ca148a 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt @@ -400,6 +400,7 @@ fun SearchBarStateless( fun HandleUIMessage( uiMessage: UIMessage?, scaffoldState: ScaffoldState, + onDisplayed: () -> Unit = {} ) { val context = LocalContext.current LaunchedEffect(uiMessage) { @@ -417,6 +418,7 @@ fun HandleUIMessage( else -> {} } + onDisplayed() } } diff --git a/core/src/main/java/org/openedx/core/ui/IAPUI.kt b/core/src/main/java/org/openedx/core/ui/IAPUI.kt new file mode 100644 index 000000000..dda585369 --- /dev/null +++ b/core/src/main/java/org/openedx/core/ui/IAPUI.kt @@ -0,0 +1,472 @@ +package org.openedx.core.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.AlertDialog +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import org.openedx.core.R +import org.openedx.core.exception.iap.IAPException +import org.openedx.core.presentation.iap.IAPAction +import org.openedx.core.presentation.iap.IAPErrorDialogType +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes +import org.openedx.core.ui.theme.appTypography + +@Composable +fun ValuePropUpgradeFeatures(modifier: Modifier = Modifier, courseName: String) { + Column( + modifier = modifier + .padding(all = 16.dp) + ) { + Text( + modifier = Modifier.padding(vertical = 32.dp), + text = stringResource( + id = R.string.iap_upgrade_course, + courseName + ), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleLarge, + maxLines = 3, + overflow = TextOverflow.Ellipsis, + ) + CheckmarkView(stringResource(id = R.string.iap_earn_certificate)) + CheckmarkView(stringResource(id = R.string.iap_unlock_access)) + CheckmarkView(stringResource(id = R.string.iap_full_access_course)) + } +} + +@Composable +fun CheckmarkView(text: String) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + modifier = Modifier.padding(end = 16.dp), + imageVector = Icons.Filled.Check, + contentDescription = null, + tint = MaterialTheme.appColors.certificateForeground + ) + Text( + modifier = Modifier.weight(1f), + text = text, + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.labelLarge + ) + } +} + +@Composable +fun IAPErrorDialog(iapException: IAPException, onIAPAction: (IAPAction) -> Unit) { + when (val dialogType = iapException.getIAPErrorDialogType()) { + IAPErrorDialogType.PRICE_ERROR_DIALOG -> { + UpgradeErrorDialog( + title = stringResource(id = R.string.iap_error_title), + description = stringResource(id = dialogType.messageResId), + confirmText = stringResource(id = dialogType.positiveButtonResId), + onConfirm = { onIAPAction(IAPAction.ACTION_RELOAD_PRICE) }, + dismissText = stringResource(id = dialogType.negativeButtonResId), + onDismiss = { onIAPAction(IAPAction.ACTION_CLOSE) } + ) + } + + IAPErrorDialogType.NO_SKU_ERROR_DIALOG -> { + NoSkuErrorDialog(onConfirm = { + onIAPAction(IAPAction.ACTION_OK) + }) + } + + IAPErrorDialogType.ADD_TO_BASKET_NOT_ACCEPTABLE_ERROR_DIALOG, + IAPErrorDialogType.CHECKOUT_NOT_ACCEPTABLE_ERROR_DIALOG -> { + UpgradeErrorDialog( + title = stringResource(id = R.string.iap_error_title), + description = stringResource(id = dialogType.messageResId), + confirmText = stringResource(id = dialogType.positiveButtonResId), + onConfirm = { onIAPAction(IAPAction.ACTION_REFRESH) }, + dismissText = stringResource(id = dialogType.negativeButtonResId), + onDismiss = { onIAPAction(IAPAction.ACTION_CLOSE) } + ) + } + + IAPErrorDialogType.EXECUTE_BAD_REQUEST_ERROR_DIALOG, + IAPErrorDialogType.EXECUTE_FORBIDDEN_ERROR_DIALOG, + IAPErrorDialogType.EXECUTE_NOT_ACCEPTABLE_ERROR_DIALOG, + IAPErrorDialogType.EXECUTE_GENERAL_ERROR_DIALOG, + IAPErrorDialogType.CONSUME_ERROR_DIALOG -> { + CourseAlreadyPurchasedExecuteErrorDialog( + description = stringResource(id = dialogType.messageResId), + positiveText = stringResource(id = dialogType.positiveButtonResId), + negativeText = stringResource(id = dialogType.negativeButtonResId), + neutralText = stringResource(id = dialogType.neutralButtonResId), + onPositiveClick = { + if (iapException.httpErrorCode == 406) { + onIAPAction(IAPAction.ACTION_REFRESH) + } else { + onIAPAction(IAPAction.ACTION_RETRY) + } + }, + onNegativeClick = { + onIAPAction(IAPAction.ACTION_GET_HELP) + }, + onNeutralClick = { + onIAPAction(IAPAction.ACTION_CLOSE) + } + ) + } + + else -> { + UpgradeErrorDialog( + title = stringResource(id = R.string.iap_error_title), + description = stringResource(id = dialogType.messageResId), + confirmText = stringResource(id = dialogType.positiveButtonResId), + onConfirm = { onIAPAction(IAPAction.ACTION_CLOSE) }, + dismissText = stringResource(id = dialogType.negativeButtonResId), + onDismiss = { onIAPAction(IAPAction.ACTION_GET_HELP) } + ) + } + } +} + +@Composable +fun NoSkuErrorDialog( + onConfirm: () -> Unit, +) { + AlertDialog( + modifier = Modifier + .background( + color = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.cardShape + ) + .padding(bottom = 8.dp), + shape = MaterialTheme.appShapes.cardShape, + backgroundColor = MaterialTheme.appColors.background, + title = { + Text( + text = stringResource(id = R.string.iap_error_title), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleMedium, + ) + }, + text = { + Text( + text = stringResource(id = R.string.iap_error_price_not_fetched), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.bodyMedium + ) + }, + confirmButton = { + OpenEdXButton( + modifier = Modifier.wrapContentSize(), + text = stringResource(id = R.string.core_ok), + onClick = onConfirm + ) + }, + onDismissRequest = onConfirm + ) +} + +@Composable +fun CourseAlreadyPurchasedExecuteErrorDialog( + description: String, + positiveText: String, + negativeText: String, + neutralText: String, + onPositiveClick: () -> Unit, + onNegativeClick: () -> Unit, + onNeutralClick: () -> Unit +) { + AlertDialog( + modifier = Modifier + .background( + color = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.cardShape + ) + .padding(bottom = 8.dp), + shape = MaterialTheme.appShapes.cardShape, + backgroundColor = MaterialTheme.appColors.background, + title = { + Text( + text = stringResource(id = R.string.iap_error_title), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleMedium, + ) + }, + text = { + Text( + text = description, + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.bodyMedium + ) + }, + buttons = { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + verticalArrangement = Arrangement.SpaceBetween, + ) { + OpenEdXButton( + modifier = Modifier + .fillMaxWidth() + .padding(2.dp), + text = positiveText, + onClick = onPositiveClick + ) + + OpenEdXButton( + modifier = Modifier + .fillMaxWidth() + .padding(2.dp), + text = negativeText, + onClick = onNegativeClick + ) + + OpenEdXButton( + modifier = Modifier + .fillMaxWidth() + .padding(2.dp), + text = neutralText, + onClick = onNeutralClick + ) + } + }, + onDismissRequest = {} + ) +} + +@Composable +fun UpgradeErrorDialog( + title: String, + description: String, + confirmText: String, + onConfirm: () -> Unit, + dismissText: String, + onDismiss: () -> Unit +) { + AlertDialog( + modifier = Modifier + .background( + color = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.cardShape + ) + .padding(bottom = 8.dp), + shape = MaterialTheme.appShapes.cardShape, + backgroundColor = MaterialTheme.appColors.background, + title = { + Text( + text = title, + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleMedium, + ) + }, + text = { + Text( + text = description, + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.bodyMedium + ) + }, + confirmButton = { + OpenEdXButton( + modifier = Modifier.wrapContentSize(), + text = confirmText, + onClick = onConfirm + ) + }, + dismissButton = { + OpenEdXButton( + modifier = Modifier.wrapContentSize(), + text = dismissText, + onClick = onDismiss + ) + }, + onDismissRequest = onConfirm + ) +} + +@Composable +fun CheckingPurchasesDialog() { + Dialog(onDismissRequest = { }) { + Column( + Modifier + .padding(16.dp) + .fillMaxWidth() + .background( + MaterialTheme.appColors.cardViewBackground, + MaterialTheme.appShapes.cardShape + ) + ) { + Text( + modifier = Modifier.padding(16.dp), + text = stringResource(id = R.string.iap_checking_purchases), + style = MaterialTheme.appTypography.titleMedium + ) + CircularProgressIndicator( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(vertical = 16.dp), + color = MaterialTheme.appColors.primary + ) + } + } +} + +@Composable +fun FakePurchasesFulfillmentCompleted(onCancel: () -> Unit, onGetHelp: () -> Unit) { + AlertDialog( + modifier = Modifier + .background( + color = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.cardShape + ) + .padding(end = 8.dp, bottom = 8.dp), + shape = MaterialTheme.appShapes.cardShape, + backgroundColor = MaterialTheme.appColors.background, + title = { + Text( + text = stringResource(id = R.string.iap_title_purchases_restored), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleMedium, + ) + }, + text = { + Text( + text = stringResource(id = R.string.iap_message_purchases_restored), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.bodyMedium, + ) + }, + confirmButton = { + OpenEdXButton( + modifier = Modifier.wrapContentSize(), + text = stringResource(id = R.string.core_cancel), + onClick = onCancel + ) + }, + dismissButton = { + OpenEdXButton( + modifier = Modifier.wrapContentSize(), + text = stringResource(id = R.string.iap_get_help), + onClick = onGetHelp + ) + }, + onDismissRequest = onCancel + ) +} + +@Composable +fun PurchasesFulfillmentCompletedDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) { + AlertDialog( + modifier = Modifier + .background( + color = MaterialTheme.appColors.background, + shape = MaterialTheme.appShapes.cardShape + ) + .padding(end = 8.dp, bottom = 8.dp), + shape = MaterialTheme.appShapes.cardShape, + backgroundColor = MaterialTheme.appColors.background, + title = { + Text( + text = stringResource(id = R.string.iap_silent_course_upgrade_success_title), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleMedium, + ) + }, + text = { + Text( + text = stringResource(id = R.string.iap_silent_course_upgrade_success_message), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.bodyMedium, + ) + }, + confirmButton = { + OpenEdXButton( + modifier = Modifier.wrapContentSize(), + text = stringResource(id = R.string.iap_label_refresh_now), + onClick = onConfirm + ) + }, + dismissButton = { + OpenEdXButton( + modifier = Modifier.wrapContentSize(), + text = stringResource(id = R.string.iap_label_continue_without_update), + onClick = onDismiss + ) + }, + onDismissRequest = onDismiss + ) +} + +@Preview +@Composable +private fun PreviewValuePropUpgradeFeatures() { + ValuePropUpgradeFeatures(modifier = Modifier.background(Color.White), "Test Course") +} + +@Preview +@Composable +private fun PreviewUpgradeErrorDialog() { + UpgradeErrorDialog( + title = "Error while Upgrading", + description = "Description of the error", + confirmText = "Confirm", + onConfirm = {}, + dismissText = "Dismiss", + onDismiss = {}) +} + +@Preview +@Composable +private fun PreviewPurchasesFulfillmentCompletedDialog() { + PurchasesFulfillmentCompletedDialog(onConfirm = {}, onDismiss = {}) +} + +@Preview +@Composable +private fun PreviewCheckingPurchasesDialog() { + CheckingPurchasesDialog() +} + +@Preview +@Composable +private fun PreviewFakePurchasesFulfillmentCompleted() { + FakePurchasesFulfillmentCompleted(onCancel = {}, onGetHelp = {}) +} + +@Preview +@Composable +private fun PreviewCourseAlreadyPurchasedExecuteErrorDialog() { + CourseAlreadyPurchasedExecuteErrorDialog( + description = stringResource(id = R.string.iap_course_not_fullfilled), + positiveText = stringResource(id = R.string.iap_label_refresh_now), + negativeText = stringResource(id = R.string.core_contact_support), + neutralText = stringResource(id = R.string.core_cancel), + onPositiveClick = {}, onNegativeClick = {}, onNeutralClick = {}) +} + +@Preview +@Composable +private fun PreviewNoSkuErrorDialog() { + NoSkuErrorDialog(onConfirm = {}) +} diff --git a/core/src/main/java/org/openedx/core/ui/UnlockingAccessView.kt b/core/src/main/java/org/openedx/core/ui/UnlockingAccessView.kt new file mode 100644 index 000000000..bf3d5bb9a --- /dev/null +++ b/core/src/main/java/org/openedx/core/ui/UnlockingAccessView.kt @@ -0,0 +1,83 @@ +package org.openedx.core.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.openedx.core.R +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appTypography + +@Composable +fun UnlockingAccessView() { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = MaterialTheme.appColors.background), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Image( + colorFilter = ColorFilter.tint(MaterialTheme.appColors.progressBarBackgroundColor), + painter = painterResource(id = R.drawable.core_ic_rocket_launch), + contentDescription = null, + ) + + val annotatedString = buildAnnotatedString { + append(stringResource(id = R.string.iap_unloacking_text)) + append("\n") + withStyle( + style = SpanStyle( + fontWeight = FontWeight.Bold, + color = MaterialTheme.appColors.primary + ) + ) { + append(stringResource(id = R.string.iap_full_access_text)) + } + append("\n") + append(stringResource(id = R.string.iap_your_course_text)) + } + + Text( + modifier = Modifier.padding(vertical = 24.dp), + text = annotatedString, + textAlign = TextAlign.Center, + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleLarge, + ) + Box( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 64.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.appColors.primary) + } + } +} + +@Preview +@Composable +private fun PreviewUnlockingAccessView() { + UnlockingAccessView() +} diff --git a/core/src/main/java/org/openedx/core/ui/UpgradeToAccessView.kt b/core/src/main/java/org/openedx/core/ui/UpgradeToAccessView.kt new file mode 100644 index 000000000..8e24936b3 --- /dev/null +++ b/core/src/main/java/org/openedx/core/ui/UpgradeToAccessView.kt @@ -0,0 +1,97 @@ +package org.openedx.core.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.Lock +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import org.openedx.core.R +import org.openedx.core.ui.theme.OpenEdXTheme +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes +import org.openedx.core.ui.theme.appTypography + +@Composable +fun UpgradeToAccessView( + modifier: Modifier = Modifier, + type: UpgradeToAccessViewType = UpgradeToAccessViewType.DASHBOARD, + onClick: () -> Unit, +) { + val shape = when (type) { + UpgradeToAccessViewType.DASHBOARD -> RoundedCornerShape( + bottomStart = 16.dp, + bottomEnd = 16.dp + ) + + UpgradeToAccessViewType.COURSE -> MaterialTheme.appShapes.buttonShape + } + Row( + modifier = modifier + .clip(shape = shape) + .fillMaxWidth() + .background(color = MaterialTheme.appColors.primaryButtonBackground) + .clickable { + onClick() + } + .padding(vertical = 8.dp, horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + modifier = Modifier.padding(end = 16.dp), + imageVector = Icons.Filled.Lock, + contentDescription = null, + tint = MaterialTheme.appColors.primaryButtonText + ) + Text( + modifier = Modifier.weight(1f), + text = stringResource(id = R.string.iap_upgrade_access_course), + color = MaterialTheme.appColors.primaryButtonText, + style = MaterialTheme.appTypography.labelLarge + ) + Icon( + modifier = Modifier.padding(start = 16.dp), + imageVector = Icons.Filled.Info, + contentDescription = null, + tint = MaterialTheme.appColors.primaryButtonText + ) + } +} + +enum class UpgradeToAccessViewType { + DASHBOARD, + COURSE, +} + +@Preview +@Composable +private fun UpgradeToAccessViewPreview( + @PreviewParameter(UpgradeToAccessViewTypeParameterProvider::class) type: UpgradeToAccessViewType +) { + OpenEdXTheme { + UpgradeToAccessView(type = type) {} + } +} + +private class UpgradeToAccessViewTypeParameterProvider : + PreviewParameterProvider { + override val values = sequenceOf( + UpgradeToAccessViewType.DASHBOARD, + UpgradeToAccessViewType.COURSE, + ) +} diff --git a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt index 5327b8cf5..5e951f9a7 100644 --- a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt +++ b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt @@ -79,7 +79,7 @@ object TimeUtils { * @return true if the other date is past today, * false otherwise. */ - private fun isDatePassed(today: Date, otherDate: Date?): Boolean { + fun isDatePassed(today: Date, otherDate: Date?): Boolean { return otherDate != null && today.after(otherDate) } diff --git a/core/src/main/res/drawable/core_ic_rocket_launch.xml b/core/src/main/res/drawable/core_ic_rocket_launch.xml new file mode 100644 index 000000000..06920c6b4 --- /dev/null +++ b/core/src/main/res/drawable/core_ic_rocket_launch.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 931d2c6da..a781df123 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -46,6 +46,7 @@ OS version: Device model: Feedback + Error upgrading course in app MMM dd, yyyy dd MMM yyyy hh:mm aaa App Update @@ -174,6 +175,7 @@ Your course calendar has been removed. Your course calendar has been updated. Error Adding Calendar, Please try later + Contact Support @@ -182,4 +184,35 @@ Discussions More Dates + + + Upgrade to access more features + Upgrade %s + Upgrade now for %s + Unlocking + full access + to your course + Get help + Earn a verified certificate of completion to showcase on your resume + Unlock access to all course activities, including graded assignments + Full access to course content and course material even after the course ends + An Error occurred + Refresh to retry + It looks like something went wrong when upgrading your course. If this error continues, please contact Support. + Error upgrading course in app + Thank you for your purchase. Enjoy full access to your course! + New experience available + An update is available to unlock a purchased course. To update, we need to quickly refresh your app. If you choose not to update now, we’ll try again later. + Refresh now + Continue without update + Checking purchases\.\.\. + Purchases have been successfully restored + All purchases are up to date. If you’re not seeing your purchases restored, please try restarting your app to refresh the experience. + Your request could not be completed at this time. If this error continues, please reach out to Support. + Your account could not be authenticated. Try signing out and signing back into the app. If this error continues, please contact Support. + The course you are looking to upgrade could not be found. Please try your upgrade again. If this error continues, contact Support. + The course you are looking to upgrade has already been paid for. For additional help, reach out to Support. + Something happened when we tried to update your course experience. If this error continues, reach out to Support for help. + Your payment could not be processed at this time. Please try again. For additional help, reach out to Support. + diff --git a/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt b/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt index 08f6cf96a..52c87456f 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CollapsingLayout.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.awaitEachGesture import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -67,6 +68,8 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.openedx.core.R import org.openedx.core.ui.RoundTabsBar +import org.openedx.core.ui.UpgradeToAccessView +import org.openedx.core.ui.UpgradeToAccessViewType import org.openedx.core.ui.displayCutoutForLandscape import org.openedx.core.ui.rememberWindowSize import org.openedx.core.ui.statusBarsInset @@ -81,6 +84,7 @@ internal fun CollapsingLayout( imageHeight: Int, expandedTop: @Composable BoxScope.() -> Unit, collapsedTop: @Composable BoxScope.() -> Unit, + upgradeButton: @Composable BoxScope.() -> Unit, navigation: @Composable BoxScope.() -> Unit, bodyContent: @Composable BoxScope.() -> Unit, onBackClick: () -> Unit, @@ -223,6 +227,7 @@ internal fun CollapsingLayout( imageHeight = imageHeight, onBackClick = onBackClick, expandedTop = expandedTop, + upgradeButton = upgradeButton, navigation = navigation, bodyContent = bodyContent ) @@ -247,6 +252,7 @@ internal fun CollapsingLayout( onBackClick = onBackClick, expandedTop = expandedTop, collapsedTop = collapsedTop, + upgradeButton = upgradeButton, navigation = navigation, bodyContent = bodyContent ) @@ -267,6 +273,7 @@ private fun CollapsingLayoutTablet( imageHeight: Int, onBackClick: () -> Unit, expandedTop: @Composable BoxScope.() -> Unit, + upgradeButton: @Composable BoxScope.() -> Unit, navigation: @Composable BoxScope.() -> Unit, bodyContent: @Composable BoxScope.() -> Unit, ) { @@ -393,20 +400,19 @@ private fun CollapsingLayoutTablet( contentDescription = null ) - - Box( - modifier = Modifier - .offset { - IntOffset( - x = 0, - y = (backgroundImageHeight.value + expandedTopHeight.value).roundToInt() - ) - } - .onSizeChanged { size -> - navigationHeight.value = size.height.toFloat() - }, - content = navigation, - ) + Column(modifier = Modifier + .offset { + IntOffset( + x = 0, + y = (backgroundImageHeight.value + expandedTopHeight.value).roundToInt() + ) + } + .onSizeChanged { size -> + navigationHeight.value = size.height.toFloat() + }) { + Box(content = upgradeButton) + Box(content = navigation) + } Box( modifier = Modifier @@ -442,6 +448,7 @@ private fun CollapsingLayoutMobile( onBackClick: () -> Unit, expandedTop: @Composable BoxScope.() -> Unit, collapsedTop: @Composable BoxScope.() -> Unit, + upgradeButton: @Composable BoxScope.() -> Unit, navigation: @Composable BoxScope.() -> Unit, bodyContent: @Composable BoxScope.() -> Unit, ) { @@ -533,15 +540,15 @@ private fun CollapsingLayoutMobile( } - Box( - modifier = Modifier - .displayCutoutForLandscape() - .offset { IntOffset(x = 0, y = (collapsedTopHeight.value).roundToInt()) } - .onSizeChanged { size -> - navigationHeight.value = size.height.toFloat() - }, - content = navigation, - ) + Column(modifier = Modifier + .displayCutoutForLandscape() + .offset { IntOffset(x = 0, y = (collapsedTopHeight.value).roundToInt()) } + .onSizeChanged { size -> + navigationHeight.value = size.height.toFloat() + }) { + Box(content = upgradeButton) + Box(content = navigation) + } Box( modifier = Modifier @@ -698,19 +705,19 @@ private fun CollapsingLayoutMobile( } val adaptiveImagePadding = blurImagePaddingPx * factor - Box( - modifier = Modifier - .offset { - IntOffset( - x = 0, - y = (offset.value + backgroundImageHeight.value + expandedTopHeight.value - adaptiveImagePadding).roundToInt() - ) - } - .onSizeChanged { size -> - navigationHeight.value = size.height.toFloat() - }, - content = navigation, - ) + Column(modifier = Modifier + .offset { + IntOffset( + x = 0, + y = (offset.value + backgroundImageHeight.value + expandedTopHeight.value - adaptiveImagePadding).roundToInt() + ) + } + .onSizeChanged { size -> + navigationHeight.value = size.height.toFloat() + }) { + Box(content = upgradeButton) + Box(content = navigation) + } Box( modifier = Modifier @@ -757,6 +764,18 @@ private fun CollapsingLayoutPreview() { courseTitle = "courseName" ) }, + upgradeButton = { + val windowSize = rememberWindowSize() + val horizontalPadding = if (!windowSize.isTablet) 16.dp else 98.dp + UpgradeToAccessView( + modifier = Modifier.padding( + start = horizontalPadding, + end = 16.dp, + top = 16.dp + ), + type = UpgradeToAccessViewType.COURSE, + ) {} + }, navigation = { RoundTabsBar( items = CourseContainerTab.entries, 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 d83cd0c18..7580b2404 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 @@ -56,12 +56,17 @@ import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import org.openedx.core.extension.takeIfNotEmpty +import org.openedx.core.presentation.IAPAnalyticsScreen +import org.openedx.core.presentation.dialog.IAPDialogFragment import org.openedx.core.presentation.global.viewBinding +import org.openedx.core.presentation.iap.IAPFlow import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialog import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.OfflineModeDialog import org.openedx.core.ui.RoundTabsBar +import org.openedx.core.ui.UpgradeToAccessView +import org.openedx.core.ui.UpgradeToAccessViewType import org.openedx.core.ui.WindowSize import org.openedx.core.ui.rememberWindowSize import org.openedx.core.ui.theme.OpenEdXTheme @@ -115,9 +120,6 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initCourseView() - if (viewModel.calendarSyncUIState.value.isCalendarSyncEnabled) { - setUpCourseCalendar() - } observe() } @@ -138,6 +140,8 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { requireActivity().supportFragmentManager, viewModel.courseName ) + } else if (viewModel.calendarSyncUIState.value.isCalendarSyncEnabled) { + setUpCourseCalendar() } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { pushNotificationPermissionLauncher.launch( @@ -305,7 +309,7 @@ fun CourseDashboard( isNavigationEnabled: Boolean, isResumed: Boolean, fragmentManager: FragmentManager, - bundle: Bundle + bundle: Bundle, ) { OpenEdXTheme { val windowSize = rememberWindowSize() @@ -321,7 +325,8 @@ fun CourseDashboard( val refreshing by viewModel.refreshing.collectAsState(true) val courseImage by viewModel.courseImage.collectAsState() val uiMessage by viewModel.uiMessage.collectAsState(null) - val openTab = bundle.getString(CourseContainerFragment.ARG_OPEN_TAB, CourseContainerTab.HOME.name) + val openTab = + bundle.getString(CourseContainerFragment.ARG_OPEN_TAB, CourseContainerTab.HOME.name) val requiredTab = when (openTab.uppercase()) { CourseContainerTab.HOME.name -> CourseContainerTab.HOME CourseContainerTab.VIDEOS.name -> CourseContainerTab.VIDEOS @@ -336,6 +341,7 @@ fun CourseDashboard( pageCount = { CourseContainerTab.entries.size } ) val dataReady = viewModel.dataReady.observeAsState() + val canShowUpgradeButton by viewModel.canShowUpgradeButton.collectAsState() val tabState = rememberLazyListState() val snackState = remember { SnackbarHostState() } val pullRefreshState = rememberPullRefreshState( @@ -366,21 +372,51 @@ fun CourseDashboard( courseImage = courseImage, imageHeight = 200, expandedTop = { - ExpandedHeaderContent( - courseTitle = viewModel.courseName, - org = viewModel.organization - ) + if (dataReady.value == true) { + ExpandedHeaderContent( + courseTitle = viewModel.courseName, + org = viewModel.courseStructure?.org!! + ) + } }, collapsedTop = { CollapsedHeaderContent( courseTitle = viewModel.courseName ) }, + upgradeButton = { + if (dataReady.value == true && canShowUpgradeButton) { + val horizontalPadding = if (!windowSize.isTablet) 16.dp else 98.dp + UpgradeToAccessView( + modifier = Modifier.padding( + start = horizontalPadding, + end = 16.dp, + top = 16.dp + ), + type = UpgradeToAccessViewType.COURSE, + ) { + IAPDialogFragment.newInstance( + iapFlow = IAPFlow.USER_INITIATED, + screenName = IAPAnalyticsScreen.COURSE_DASHBOARD.screenName, + courseId = viewModel.courseId, + courseName = viewModel.courseName, + isSelfPaced = viewModel.courseStructure?.isSelfPaced!!, + productInfo = viewModel.courseStructure?.productInfo!! + ).show( + fragmentManager, + IAPDialogFragment.TAG + ) + } + } + }, navigation = { if (isNavigationEnabled) { RoundTabsBar( items = CourseContainerTab.entries, - contentPadding = PaddingValues(horizontal = 12.dp, vertical = 16.dp), + contentPadding = PaddingValues( + horizontal = 12.dp, + vertical = 16.dp + ), rowState = tabState, pagerState = pagerState, withPager = true, @@ -459,7 +495,7 @@ fun DashboardPager( isNavigationEnabled: Boolean, isResumed: Boolean, fragmentManager: FragmentManager, - bundle: Bundle, + bundle: Bundle ) { HorizontalPager( state = pagerState, 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 60813d29a..b4a846b09 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 @@ -15,6 +15,9 @@ import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.openedx.core.BaseViewModel @@ -23,8 +26,10 @@ import org.openedx.core.SingleEventLiveData import org.openedx.core.UIMessage import org.openedx.core.config.Config import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.model.CourseStructure import org.openedx.core.exception.NoCachedDataException import org.openedx.core.extension.isInternetError +import org.openedx.core.presentation.global.AppData import org.openedx.core.presentation.settings.calendarsync.CalendarSyncDialogType import org.openedx.core.presentation.settings.calendarsync.CalendarSyncUIState import org.openedx.core.system.CalendarManager @@ -33,13 +38,16 @@ import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CalendarSyncEvent.CheckCalendarSyncEvent import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent import org.openedx.core.system.notifier.CourseCompletionSet +import org.openedx.core.system.notifier.CourseDataUpdated import org.openedx.core.system.notifier.CourseDatesShifted import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseOpenBlock import org.openedx.core.system.notifier.CourseStructureUpdated +import org.openedx.core.system.notifier.IAPNotifier import org.openedx.core.system.notifier.RefreshDates import org.openedx.core.system.notifier.RefreshDiscussions +import org.openedx.core.system.notifier.UpdateCourseData import org.openedx.core.utils.TimeUtils import org.openedx.course.DatesShiftedSnackBar import org.openedx.course.data.storage.CoursePreferences @@ -59,11 +67,13 @@ class CourseContainerViewModel( var courseName: String, private var resumeBlockId: String, private val enrollmentMode: String, + private val appData: AppData, private val config: Config, private val interactor: CourseInteractor, private val calendarManager: CalendarManager, private val resourceManager: ResourceManager, private val courseNotifier: CourseNotifier, + private val iapNotifier: IAPNotifier, private val networkConnection: NetworkConnection, private val corePreferences: CorePreferences, private val coursePreferences: CoursePreferences, @@ -96,20 +106,30 @@ class CourseContainerViewModel( val uiMessage: SharedFlow get() = _uiMessage.asSharedFlow() - private var _isSelfPaced: Boolean = true - val isSelfPaced: Boolean - get() = _isSelfPaced + private val isValuePropEnabled: Boolean + get() = corePreferences.appConfig.isValuePropEnabled - private var _organization: String = "" - val organization: String - get() = _organization + private val iapConfig + get() = corePreferences.appConfig.iapConfig + + private val isIAPEnabled + get() = iapConfig.isEnabled && + iapConfig.disableVersions.contains(appData.versionName).not() + + private var _canShowUpgradeButton = MutableStateFlow(false) + val canShowUpgradeButton: StateFlow + get() = _canShowUpgradeButton.asStateFlow() + + private var _courseStructure: CourseStructure? = null + val courseStructure: CourseStructure? + get() = _courseStructure val calendarPermissions: Array get() = calendarManager.permissions private val _calendarSyncUIState = MutableStateFlow( CalendarSyncUIState( - isCalendarSyncEnabled = isCalendarSyncEnabled(), + isCalendarSyncEnabled = false, calendarTitle = calendarManager.getCourseCalendarTitle(courseName), courseDates = emptyList(), dialogType = CalendarSyncDialogType.NONE, @@ -162,6 +182,14 @@ class CourseContainerViewModel( } } } + + iapNotifier.notifier.onEach { event -> + when (event) { + is UpdateCourseData -> { + updateData(true) + } + } + }.distinctUntilChanged().launchIn(viewModelScope) } fun preloadCourseStructure() { @@ -169,21 +197,26 @@ class CourseContainerViewModel( if (_dataReady.value != null) { return } - _showProgress.value = true viewModelScope.launch { try { - val courseStructure = interactor.getCourseStructure(courseId, true) - courseName = courseStructure.name - _organization = courseStructure.org - _isSelfPaced = courseStructure.isSelfPaced - loadCourseImage(courseStructure.media?.image?.large) - _dataReady.value = courseStructure.start?.let { start -> - val isReady = start < Date() - if (isReady) { - _isNavigationEnabled.value = true + _courseStructure = interactor.getCourseStructure(courseId, true) + _courseStructure?.let { + courseName = it.name + loadCourseImage(courseStructure?.media?.image?.large) + _calendarSyncUIState.update { state -> + state.copy(isCalendarSyncEnabled = isCalendarSyncEnabled()) } - isReady + _dataReady.value = courseStructure?.start?.let { start -> + val isReady = start < Date() + if (isReady) { + _isNavigationEnabled.value = true + } + isReady + } + _canShowUpgradeButton.value = isIAPEnabled && + isValuePropEnabled && + courseStructure?.isUpgradeable == true } if (_dataReady.value == true && resumeBlockId.isNotEmpty()) { delay(500L) @@ -247,10 +280,14 @@ class CourseContainerViewModel( } } - fun updateData() { + fun updateData(isIAPFlow: Boolean = false) { viewModelScope.launch { try { - interactor.getCourseStructure(courseId, isNeedRefresh = true) + _courseStructure = interactor.getCourseStructure(courseId, isNeedRefresh = true) + _canShowUpgradeButton.value = isIAPEnabled && + isValuePropEnabled && + courseStructure?.productInfo != null && + courseStructure?.isUpgradeable == true } catch (e: Exception) { if (e.isInternetError()) { _errorMessage.value = @@ -262,6 +299,9 @@ class CourseContainerViewModel( } _refreshing.value = false courseNotifier.send(CourseStructureUpdated(courseId)) + if (isIAPFlow) { + iapNotifier.send(CourseDataUpdated()) + } } } @@ -391,8 +431,8 @@ class CourseContainerViewModel( private fun isCalendarSyncEnabled(): Boolean { val calendarSync = corePreferences.appConfig.courseDatesCalendarSync - return calendarSync.isEnabled && ((calendarSync.isSelfPacedEnabled && isSelfPaced) || - (calendarSync.isInstructorPacedEnabled && !isSelfPaced)) + return calendarSync.isEnabled && ((calendarSync.isSelfPacedEnabled && _courseStructure?.isSelfPaced == true) || + (calendarSync.isInstructorPacedEnabled && _courseStructure?.isSelfPaced == false)) } private fun courseDashboardViewed() { @@ -484,7 +524,7 @@ class CourseContainerViewModel( put(CourseAnalyticsKey.ENROLLMENT_MODE.key, enrollmentMode) put( CourseAnalyticsKey.PACING.key, - if (isSelfPaced) CourseAnalyticsKey.SELF_PACED.key + if (_courseStructure?.isSelfPaced == true) CourseAnalyticsKey.SELF_PACED.key else CourseAnalyticsKey.INSTRUCTOR_PACED.key ) putAll(param) diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt index 1f31b32de..69e930d9c 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineScreen.kt @@ -49,9 +49,11 @@ import org.openedx.core.UIMessage import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseAccessDetails 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.domain.model.EnrollmentDetails import org.openedx.core.domain.model.Progress import org.openedx.core.extension.takeIfNotEmpty import org.openedx.core.presentation.course.CourseViewMode @@ -80,9 +82,9 @@ fun CourseOutlineScreen( fragmentManager: FragmentManager, onResetDatesClick: () -> Unit ) { + val resumeBlockId by viewModel.resumeBlockId.collectAsState("") val uiState by viewModel.uiState.collectAsState() val uiMessage by viewModel.uiMessage.collectAsState(null) - val resumeBlockId by viewModel.resumeBlockId.collectAsState("") val context = LocalContext.current LaunchedEffect(resumeBlockId) { @@ -168,7 +170,7 @@ private fun CourseOutlineUI( onResumeClick: (String) -> Unit, onDownloadClick: (blockIds: List) -> Unit, onResetDatesClick: () -> Unit, - onCertificateClick: (String) -> Unit, + onCertificateClick: (String) -> Unit ) { val scaffoldState = rememberScaffoldState() @@ -512,7 +514,7 @@ private fun CourseOutlineScreenPreview() { onResumeClick = {}, onDownloadClick = {}, onResetDatesClick = {}, - onCertificateClick = {}, + onCertificateClick = {} ) } } @@ -545,7 +547,7 @@ private fun CourseOutlineScreenTabletPreview() { onResumeClick = {}, onDownloadClick = {}, onResetDatesClick = {}, - onCertificateClick = {}, + onCertificateClick = {} ) } } @@ -603,6 +605,21 @@ private val mockSequentialBlock = Block( due = Date() ) +private val mockEnrollmentDetails = + EnrollmentDetails(created = Date(), mode = "audit", isActive = false, upgradeDeadline = Date()) + +private val mockCourseAccessDetails = CourseAccessDetails( + Date(), + coursewareAccess = CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) +) + private val mockCourseStructure = CourseStructure( root = "", blockData = listOf(mockSequentialBlock, mockSequentialBlock), @@ -614,16 +631,11 @@ private val mockCourseStructure = CourseStructure( startDisplay = "", startType = "", end = Date(), - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, certificate = null, isSelfPaced = false, - progress = Progress(1, 3) + progress = Progress(1, 3), + productInfo = null, + enrollmentDetails = mockEnrollmentDetails, + courseAccessDetails = mockCourseAccessDetails ) 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 b65b3b62a..1dcf7dd25 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 @@ -117,7 +117,7 @@ class CourseOutlineViewModel( courseSubSections = courseSubSections, courseSectionsState = state.courseSectionsState, subSectionsDownloadsCount = subSectionsDownloadsCount, - datesBannerInfo = state.datesBannerInfo, + datesBannerInfo = state.datesBannerInfo ) } } @@ -164,7 +164,7 @@ class CourseOutlineViewModel( courseSubSections = courseSubSections, courseSectionsState = courseSectionsState, subSectionsDownloadsCount = subSectionsDownloadsCount, - datesBannerInfo = state.datesBannerInfo, + datesBannerInfo = state.datesBannerInfo ) courseSectionsState[blockId] ?: false @@ -220,7 +220,7 @@ class CourseOutlineViewModel( courseSubSections = courseSubSections, courseSectionsState = courseSectionsState, subSectionsDownloadsCount = subSectionsDownloadsCount, - datesBannerInfo = datesBannerInfo, + datesBannerInfo = datesBannerInfo ) courseNotifier.send(CourseLoading(false)) } catch (e: Exception) { 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 b111dd1f0..5dd7c0d2b 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 @@ -664,7 +664,8 @@ fun CourseExpandableChapterCard( if (block.isCompleted()) { val completedIconPainter = painterResource(R.drawable.course_ic_task_alt) val completedIconColor = MaterialTheme.appColors.successGreen - val completedIconDescription = stringResource(id = R.string.course_accessibility_section_completed) + val completedIconDescription = + stringResource(id = R.string.course_accessibility_section_completed) Icon( painter = completedIconPainter, @@ -750,13 +751,16 @@ fun CourseSubSectionItem( ) { val context = LocalContext.current val icon = - if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource(coreR.drawable.ic_core_chapter_icon) + if (block.isCompleted()) painterResource(R.drawable.course_ic_task_alt) else painterResource( + coreR.drawable.ic_core_chapter_icon + ) val iconColor = if (block.isCompleted()) MaterialTheme.appColors.successGreen else MaterialTheme.appColors.onSurface val due by rememberSaveable { mutableStateOf(block.due?.let { TimeUtils.getAssignmentFormattedDate(context, it) }) } - val isAssignmentEnable = !block.isCompleted() && block.assignmentProgress != null && !due.isNullOrEmpty() + val isAssignmentEnable = + !block.isCompleted() && block.assignmentProgress != null && !due.isNullOrEmpty() Column( modifier = modifier .fillMaxWidth() diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt index 1a406181d..f7c0f85b6 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseVideosUI.kt @@ -60,8 +60,10 @@ import org.openedx.core.UIMessage import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.domain.model.Progress import org.openedx.core.domain.model.VideoSettings import org.openedx.core.extension.toFileSize @@ -741,6 +743,21 @@ private val mockSequentialBlock = Block( due = Date() ) +private val mockEnrollmentDetails = + EnrollmentDetails(created = Date(), mode = "audit", isActive = false, upgradeDeadline = Date()) + +private val mockCourseAccessDetails = CourseAccessDetails( + Date(), + coursewareAccess = CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) +) + private val mockCourseStructure = CourseStructure( root = "", blockData = listOf(mockSequentialBlock, mockChapterBlock), @@ -752,16 +769,11 @@ private val mockCourseStructure = CourseStructure( startDisplay = "", startType = "", end = Date(), - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, + courseAccessDetails = mockCourseAccessDetails, certificate = null, isSelfPaced = false, - progress = Progress(1, 3) + progress = Progress(1, 3), + productInfo = null, + enrollmentDetails = mockEnrollmentDetails ) diff --git a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt index f049e3751..158fb5440 100644 --- a/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/container/CourseContainerViewModelTest.kt @@ -30,14 +30,18 @@ import org.openedx.core.data.model.CourseStructureModel import org.openedx.core.data.model.User import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.AppConfig +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseDatesCalendarSync import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrollmentDetails +import org.openedx.core.presentation.global.AppData import org.openedx.core.system.CalendarManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CourseNotifier import org.openedx.core.system.notifier.CourseStructureUpdated +import org.openedx.core.system.notifier.IAPNotifier import org.openedx.course.data.storage.CoursePreferences import org.openedx.course.domain.interactor.CourseInteractor import org.openedx.course.presentation.CourseAnalytics @@ -59,7 +63,8 @@ class CourseContainerViewModelTest { private val interactor = mockk() private val calendarManager = mockk() private val networkConnection = mockk() - private val notifier = spyk() + private val courseNotifier = spyk() + private val iapNotifier = spyk() private val analytics = mockk() private val corePreferences = mockk() private val coursePreferences = mockk() @@ -67,6 +72,7 @@ class CourseContainerViewModelTest { private val imageProcessor = mockk() private val courseRouter = mockk() private val courseApi = mockk() + private val appData = mockk() private val openEdx = "OpenEdx" private val calendarTitle = "OpenEdx - Abc" @@ -98,18 +104,27 @@ class CourseContainerViewModelTest { startDisplay = "", startType = "", end = null, - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, + courseAccessDetails = CourseAccessDetails( + Date(), coursewareAccess = CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) + ), certificate = null, isSelfPaced = false, - progress = null + progress = null, + enrollmentDetails = EnrollmentDetails( + created = Date(), + mode = "audit", + isActive = false, + upgradeDeadline = Date() + ), + productInfo = null ) private val courseStructureModel = CourseStructureModel( @@ -123,11 +138,16 @@ class CourseContainerViewModelTest { startDisplay = "", startType = "", end = null, - coursewareAccess = null, + courseAccessDetails = org.openedx.core.data.model.CourseAccessDetails( + "", + coursewareAccess = null + ), media = null, certificate = null, isSelfPaced = false, - progress = null + progress = null, + enrollmentDetails = org.openedx.core.data.model.EnrollmentDetails("", "", false, ""), + courseModes = arrayListOf() ) @Before @@ -138,7 +158,7 @@ class CourseContainerViewModelTest { every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong every { corePreferences.user } returns user every { corePreferences.appConfig } returns appConfig - every { notifier.notifier } returns emptyFlow() + every { courseNotifier.notifier } returns emptyFlow() every { calendarManager.getCourseCalendarTitle(any()) } returns calendarTitle every { config.getApiHostURL() } returns "baseUrl" every { imageProcessor.loadImage(any(), any(), any()) } returns Unit @@ -157,11 +177,13 @@ class CourseContainerViewModelTest { "", "", "", + appData, config, interactor, calendarManager, resourceManager, - notifier, + courseNotifier, + iapNotifier, networkConnection, corePreferences, coursePreferences, @@ -191,11 +213,13 @@ class CourseContainerViewModelTest { "", "", "", + appData, config, interactor, calendarManager, resourceManager, - notifier, + courseNotifier, + iapNotifier, networkConnection, corePreferences, coursePreferences, @@ -225,11 +249,13 @@ class CourseContainerViewModelTest { "", "", "", + appData, config, interactor, calendarManager, resourceManager, - notifier, + courseNotifier, + iapNotifier, networkConnection, corePreferences, coursePreferences, @@ -258,11 +284,13 @@ class CourseContainerViewModelTest { "", "", "", + appData, config, interactor, calendarManager, resourceManager, - notifier, + courseNotifier, + iapNotifier, networkConnection, corePreferences, coursePreferences, @@ -294,11 +322,13 @@ class CourseContainerViewModelTest { "", "", "", + appData, config, interactor, calendarManager, resourceManager, - notifier, + courseNotifier, + iapNotifier, networkConnection, corePreferences, coursePreferences, @@ -307,7 +337,7 @@ class CourseContainerViewModelTest { courseRouter ) coEvery { interactor.getCourseStructure(any(), true) } throws UnknownHostException() - coEvery { notifier.send(CourseStructureUpdated("")) } returns Unit + coEvery { courseNotifier.send(CourseStructureUpdated("")) } returns Unit viewModel.updateData() advanceUntilIdle() @@ -325,11 +355,13 @@ class CourseContainerViewModelTest { "", "", "", + appData, config, interactor, calendarManager, resourceManager, - notifier, + courseNotifier, + iapNotifier, networkConnection, corePreferences, coursePreferences, @@ -338,7 +370,7 @@ class CourseContainerViewModelTest { courseRouter ) coEvery { interactor.getCourseStructure(any(), true) } throws Exception() - coEvery { notifier.send(CourseStructureUpdated("")) } returns Unit + coEvery { courseNotifier.send(CourseStructureUpdated("")) } returns Unit viewModel.updateData() advanceUntilIdle() @@ -356,11 +388,13 @@ class CourseContainerViewModelTest { "", "", "", + appData, config, interactor, calendarManager, resourceManager, - notifier, + courseNotifier, + iapNotifier, networkConnection, corePreferences, coursePreferences, @@ -369,7 +403,7 @@ class CourseContainerViewModelTest { courseRouter ) coEvery { interactor.getCourseStructure(any(), true) } returns courseStructure - coEvery { notifier.send(CourseStructureUpdated("")) } returns Unit + coEvery { courseNotifier.send(CourseStructureUpdated("")) } returns Unit viewModel.updateData() advanceUntilIdle() diff --git a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt index 11ffb4932..38ae28d8d 100644 --- a/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/dates/CourseDatesViewModelTest.kt @@ -30,6 +30,7 @@ import org.openedx.core.data.model.DateType import org.openedx.core.data.model.User import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.AppConfig +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseDateBlock import org.openedx.core.domain.model.CourseDatesBannerInfo import org.openedx.core.domain.model.CourseDatesCalendarSync @@ -37,6 +38,7 @@ import org.openedx.core.domain.model.CourseDatesResult import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.DatesSection +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.system.CalendarManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CalendarSyncEvent.CreateCalendarSyncEvent @@ -125,18 +127,25 @@ class CourseDatesViewModelTest { startDisplay = "", startType = "", end = null, - coursewareAccess = CoursewareAccess( + media = null, + courseAccessDetails = CourseAccessDetails(Date(), CoursewareAccess( true, "", "", "", "", "" - ), - media = null, + )), certificate = null, isSelfPaced = true, - progress = null + progress = null, + enrollmentDetails = EnrollmentDetails( + created = Date(), + mode = "audit", + isActive = false, + upgradeDeadline = Date() + ), + productInfo = null ) @Before 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 aad650b28..4fe06e1a7 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 @@ -36,6 +36,7 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseComponentStatus import org.openedx.core.domain.model.CourseDateBlock import org.openedx.core.domain.model.CourseDatesBannerInfo @@ -43,6 +44,7 @@ import org.openedx.core.domain.model.CourseDatesResult import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.DatesSection +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.module.DownloadWorkerController import org.openedx.core.module.db.DownloadDao import org.openedx.core.module.db.DownloadModel @@ -159,18 +161,22 @@ class CourseOutlineViewModelTest { startDisplay = "", startType = "", end = Date(), - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, + courseAccessDetails = CourseAccessDetails( + Date(), CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) + ), + enrollmentDetails = EnrollmentDetails(Date(), "audit", false, Date()), certificate = null, isSelfPaced = false, - progress = null + progress = null, + productInfo = null ) private val dateBlock = CourseDateBlock( @@ -604,4 +610,4 @@ class CourseOutlineViewModelTest { assert(message.await()?.message.isNullOrEmpty()) } -} +} \ No newline at end of file diff --git a/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt index 01c685c48..1b0d01fd0 100644 --- a/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/section/CourseSectionViewModelTest.kt @@ -30,8 +30,10 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.module.DownloadWorkerController import org.openedx.core.module.db.DownloadDao import org.openedx.core.module.db.DownloadModel @@ -144,18 +146,27 @@ class CourseSectionViewModelTest { startDisplay = "", startType = "", end = Date(), - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, + courseAccessDetails = CourseAccessDetails( + Date(), CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) + ), certificate = null, isSelfPaced = false, - progress = null + progress = null, + enrollmentDetails = EnrollmentDetails( + created = Date(), + mode = "audit", + isActive = false, + upgradeDeadline = Date() + ), + productInfo = null ) private val downloadModel = DownloadModel( diff --git a/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt index 166d7751e..577c3d41d 100644 --- a/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModelTest.kt @@ -23,8 +23,10 @@ import org.openedx.core.config.Config import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.presentation.course.CourseViewMode import org.openedx.core.system.notifier.CourseNotifier import org.openedx.course.domain.interactor.CourseInteractor @@ -138,18 +140,27 @@ class CourseUnitContainerViewModelTest { startDisplay = "", startType = "", end = Date(), - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, + courseAccessDetails = CourseAccessDetails( + Date(), CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) + ), certificate = null, isSelfPaced = false, - progress = null + progress = null, + enrollmentDetails = EnrollmentDetails( + created = Date(), + mode = "audit", + isActive = false, + upgradeDeadline = Date() + ), + productInfo = null ) @Before diff --git a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt index 9bb8d0f5f..26417a9d1 100644 --- a/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/videos/CourseVideoViewModelTest.kt @@ -35,8 +35,10 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.domain.model.VideoSettings import org.openedx.core.module.DownloadWorkerController import org.openedx.core.module.db.DownloadDao @@ -153,18 +155,22 @@ class CourseVideoViewModelTest { startDisplay = "", startType = "", end = Date(), - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, + courseAccessDetails = CourseAccessDetails( + Date(), CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) + ), + enrollmentDetails = EnrollmentDetails(Date(), "audit", false, Date()), certificate = null, isSelfPaced = false, - progress = null + progress = null, + productInfo = null ) private val downloadModelEntity = @@ -350,84 +356,86 @@ class CourseVideoViewModelTest { } @Test - fun `saveDownloadModels only wifi download, with connection`() = runTest(UnconfinedTestDispatcher()) { - every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false - every { preferencesManager.videoSettings } returns VideoSettings.default - val viewModel = CourseVideoViewModel( - "", - "", - config, - interactor, - resourceManager, - networkConnection, - preferencesManager, - courseNotifier, - videoNotifier, - analytics, - courseRouter, - coreAnalytics, - downloadDao, - workerController - ) - coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } - every { preferencesManager.videoSettings.wifiDownloadOnly } returns true - every { networkConnection.isWifiConnected() } returns true - coEvery { workerController.saveModels(any()) } returns Unit - coEvery { downloadDao.readAllData() } returns flow { - emit(listOf(DownloadModelEntity.createFrom(downloadModel))) - } - every { coreAnalytics.logEvent(any(), any()) } returns Unit - val message = async { - withTimeoutOrNull(5000) { - viewModel.uiMessage.first() as? UIMessage.SnackBarMessage + fun `saveDownloadModels only wifi download, with connection`() = + runTest(UnconfinedTestDispatcher()) { + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false + every { preferencesManager.videoSettings } returns VideoSettings.default + val viewModel = CourseVideoViewModel( + "", + "", + config, + interactor, + resourceManager, + networkConnection, + preferencesManager, + courseNotifier, + videoNotifier, + analytics, + courseRouter, + coreAnalytics, + downloadDao, + workerController + ) + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure + coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } + every { preferencesManager.videoSettings.wifiDownloadOnly } returns true + every { networkConnection.isWifiConnected() } returns true + coEvery { workerController.saveModels(any()) } returns Unit + coEvery { downloadDao.readAllData() } returns flow { + emit(listOf(DownloadModelEntity.createFrom(downloadModel))) + } + every { coreAnalytics.logEvent(any(), any()) } returns Unit + val message = async { + withTimeoutOrNull(5000) { + viewModel.uiMessage.first() as? UIMessage.SnackBarMessage + } } - } - viewModel.saveDownloadModels("", "") - advanceUntilIdle() + viewModel.saveDownloadModels("", "") + advanceUntilIdle() - assert(message.await()?.message.isNullOrEmpty()) - } + assert(message.await()?.message.isNullOrEmpty()) + } @Test - fun `saveDownloadModels only wifi download, without connection`() = runTest(UnconfinedTestDispatcher()) { - every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false - every { preferencesManager.videoSettings } returns VideoSettings.default - val viewModel = CourseVideoViewModel( - "", - "", - config, - interactor, - resourceManager, - networkConnection, - preferencesManager, - courseNotifier, - videoNotifier, - analytics, - courseRouter, - coreAnalytics, - downloadDao, - workerController - ) - every { preferencesManager.videoSettings.wifiDownloadOnly } returns true - every { networkConnection.isWifiConnected() } returns false - every { networkConnection.isOnline() } returns false - coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure - coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } - coEvery { workerController.saveModels(any()) } returns Unit - val message = async { - withTimeoutOrNull(5000) { - viewModel.uiMessage.first() as? UIMessage.SnackBarMessage + fun `saveDownloadModels only wifi download, without connection`() = + runTest(UnconfinedTestDispatcher()) { + every { config.getCourseUIConfig().isCourseDropdownNavigationEnabled } returns false + every { preferencesManager.videoSettings } returns VideoSettings.default + val viewModel = CourseVideoViewModel( + "", + "", + config, + interactor, + resourceManager, + networkConnection, + preferencesManager, + courseNotifier, + videoNotifier, + analytics, + courseRouter, + coreAnalytics, + downloadDao, + workerController + ) + every { preferencesManager.videoSettings.wifiDownloadOnly } returns true + every { networkConnection.isWifiConnected() } returns false + every { networkConnection.isOnline() } returns false + coEvery { interactor.getCourseStructureForVideos(any()) } returns courseStructure + coEvery { downloadDao.readAllData() } returns flow { emit(listOf(downloadModelEntity)) } + coEvery { workerController.saveModels(any()) } returns Unit + val message = async { + withTimeoutOrNull(5000) { + viewModel.uiMessage.first() as? UIMessage.SnackBarMessage + } } - } - viewModel.saveDownloadModels("", "") + viewModel.saveDownloadModels("", "") - advanceUntilIdle() + advanceUntilIdle() - assert(message.await()?.message.isNullOrEmpty()) - } + assert(message.await()?.message.isNullOrEmpty()) + } -} +} \ No newline at end of file diff --git a/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt b/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt index f3b6a5aee..3a1395f5c 100644 --- a/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt +++ b/dashboard/src/androidTest/java/org/openedx/dashboard/presentation/MyCoursesScreenTest.kt @@ -17,6 +17,7 @@ import org.openedx.core.domain.model.CourseSharingUtmParameters import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.EnrolledCourse import org.openedx.core.domain.model.EnrolledCourseData +import org.openedx.core.presentation.iap.IAPUIState import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType import java.util.Date @@ -42,7 +43,7 @@ class MyCoursesScreenTest { startDisplay = "", startType = "", end = null, - dynamicUpgradeDeadline = "", + upgradeDeadline = "", subscriptionId = "", coursewareAccess = CoursewareAccess( true, @@ -61,7 +62,8 @@ class MyCoursesScreenTest { discussionUrl = "", videoOutline = "", isSelfPaced = false - ) + ), + productInfo = null ) //endregion @@ -71,17 +73,23 @@ class MyCoursesScreenTest { DashboardListView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", - state = DashboardUIState.Courses(listOf(mockCourseEnrolled, mockCourseEnrolled)), + state = DashboardUIState.Courses( + listOf(mockCourseEnrolled, mockCourseEnrolled), + false + ), uiMessage = null, - refreshing = false, canLoadMore = false, + refreshing = false, hasInternetConnection = true, onReloadClick = {}, onSwipeRefresh = {}, paginationCallback = {}, onItemClick = {}, appUpgradeParameters = AppUpdateState.AppUpgradeParameters(), - onSettingsClick = {} + onSettingsClick = {}, + iapCallback = { _, _ -> }, + onGetHelp = {}, + iapState = IAPUIState.Clear, ) } @@ -104,17 +112,23 @@ class MyCoursesScreenTest { DashboardListView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", - state = DashboardUIState.Courses(listOf(mockCourseEnrolled, mockCourseEnrolled)), + state = DashboardUIState.Courses( + listOf(mockCourseEnrolled, mockCourseEnrolled), + false + ), uiMessage = null, - refreshing = false, canLoadMore = false, + refreshing = false, hasInternetConnection = true, onReloadClick = {}, onSwipeRefresh = {}, paginationCallback = {}, onItemClick = {}, appUpgradeParameters = AppUpdateState.AppUpgradeParameters(), - onSettingsClick = {} + onSettingsClick = {}, + iapCallback = { _, _ -> }, + onGetHelp = {}, + iapState = IAPUIState.Clear, ) } @@ -130,17 +144,23 @@ class MyCoursesScreenTest { DashboardListView( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", - state = DashboardUIState.Courses(listOf(mockCourseEnrolled, mockCourseEnrolled)), + state = DashboardUIState.Courses( + listOf(mockCourseEnrolled, mockCourseEnrolled), + false + ), uiMessage = null, - refreshing = true, canLoadMore = false, + refreshing = true, hasInternetConnection = true, onReloadClick = {}, onSwipeRefresh = {}, paginationCallback = {}, onItemClick = {}, appUpgradeParameters = AppUpdateState.AppUpgradeParameters(), - onSettingsClick = {} + onSettingsClick = {}, + iapCallback = { _, _ -> }, + onGetHelp = {}, + iapState = IAPUIState.Clear, ) } @@ -162,5 +182,4 @@ class MyCoursesScreenTest { ) } } - } diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt index 3392ed7bd..41e49e7a4 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt @@ -152,7 +152,11 @@ fun AllEnrolledCoursesView( ) } -@OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class) +@OptIn( + ExperimentalMaterialApi::class, + ExperimentalComposeUiApi::class, + ExperimentalFoundationApi::class +) @Composable private fun AllEnrolledCoursesView( apiHostUrl: String, @@ -271,7 +275,9 @@ private fun AllEnrolledCoursesView( Header( modifier = Modifier .padding( - start = contentPaddings.calculateStartPadding(layoutDirection), + start = contentPaddings.calculateStartPadding( + layoutDirection + ), end = contentPaddings.calculateEndPadding(layoutDirection) ), onSearchClick = { @@ -324,7 +330,11 @@ private fun AllEnrolledCoursesView( course = course, apiHostUrl = apiHostUrl, onClick = { - onAction(AllEnrolledCoursesAction.OpenCourse(it)) + onAction( + AllEnrolledCoursesAction.OpenCourse( + it + ) + ) } ) } @@ -616,7 +626,7 @@ private val mockCourseEnrolled = EnrolledCourse( startDisplay = "", startType = "", end = Date(), - dynamicUpgradeDeadline = "", + upgradeDeadline = "", subscriptionId = "", coursewareAccess = CoursewareAccess( false, @@ -635,5 +645,6 @@ private val mockCourseEnrolled = EnrolledCourse( discussionUrl = "", videoOutline = "", isSelfPaced = false - ) + ), + productInfo = null ) diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt index 7401f6304..2dbdeae55 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt @@ -223,7 +223,12 @@ private fun DashboardGalleryView( onAction(DashboardGalleryScreenAction.NavigateToDates(it)) }, resumeBlockId = { course, blockId -> - onAction(DashboardGalleryScreenAction.OpenBlock(course, blockId)) + onAction( + DashboardGalleryScreenAction.OpenBlock( + course, + blockId + ) + ) } ) } @@ -606,7 +611,10 @@ private fun PrimaryCourseCard( if (primaryCourse.courseStatus == null) { openCourse(primaryCourse) } else { - resumeBlockId(primaryCourse, primaryCourse.courseStatus?.lastVisitedBlockId ?: "") + resumeBlockId( + primaryCourse, + primaryCourse.courseStatus?.lastVisitedBlockId ?: "" + ) } } ) @@ -803,7 +811,7 @@ private val mockCourse = EnrolledCourse( startDisplay = "", startType = "", end = Date(), - dynamicUpgradeDeadline = "", + upgradeDeadline = "", subscriptionId = "", coursewareAccess = CoursewareAccess( true, @@ -822,8 +830,10 @@ private val mockCourse = EnrolledCourse( discussionUrl = "", videoOutline = "", isSelfPaced = false - ) + ), + productInfo = null ) + private val mockPagination = Pagination(10, "", 4, "1") private val mockDashboardCourseList = DashboardCourseList( pagination = mockPagination, diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index 2d8e81d6b..e3bfe2dc3 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -40,6 +40,8 @@ import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableIntStateOf @@ -81,10 +83,20 @@ import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.domain.model.EnrolledCourse import org.openedx.core.domain.model.EnrolledCourseData import org.openedx.core.domain.model.Progress +import org.openedx.core.domain.model.iap.ProductInfo +import org.openedx.core.exception.iap.IAPException +import org.openedx.core.presentation.IAPAnalyticsScreen +import org.openedx.core.presentation.dialog.IAPDialogFragment import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRecommendedBox +import org.openedx.core.presentation.iap.IAPAction +import org.openedx.core.presentation.iap.IAPFlow +import org.openedx.core.presentation.iap.IAPUIState import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.OfflineModeDialog +import org.openedx.core.ui.PurchasesFulfillmentCompletedDialog +import org.openedx.core.ui.UpgradeErrorDialog +import org.openedx.core.ui.UpgradeToAccessView import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType import org.openedx.core.ui.displayCutoutForLandscape @@ -124,12 +136,14 @@ class DashboardListFragment : Fragment() { val refreshing by viewModel.updating.observeAsState(false) val canLoadMore by viewModel.canLoadMore.observeAsState(false) val appUpgradeEvent by viewModel.appUpgradeEvent.observeAsState() + val iapUiState by viewModel.iapUiState.collectAsState(null) DashboardListView( windowSize = windowSize, viewModel.apiHostUrl, - uiState!!, - uiMessage, + state = uiState!!, + uiMessage = uiMessage, + iapUiState = iapUiState, canLoadMore = canLoadMore, refreshing = refreshing, hasInternetConnection = viewModel.hasInternetConnection, @@ -157,6 +171,57 @@ class DashboardListFragment : Fragment() { AppUpdateState.openPlayMarket(requireContext()) }, ), + onIAPAction = { action, course, iapException -> + when (action) { + IAPAction.ACTION_USER_INITIATED -> { + if (course != null) { + IAPDialogFragment.newInstance( + iapFlow = IAPFlow.USER_INITIATED, + screenName = IAPAnalyticsScreen.COURSE_ENROLLMENT.screenName, + courseId = course.course.id, + courseName = course.course.name, + isSelfPaced = course.course.isSelfPaced, + productInfo = course.productInfo!! + ).show( + requireActivity().supportFragmentManager, + IAPDialogFragment.TAG + ) + } + } + + IAPAction.ACTION_COMPLETION -> { + IAPDialogFragment.newInstance( + IAPFlow.SILENT, + IAPAnalyticsScreen.COURSE_ENROLLMENT.screenName + ).show( + requireActivity().supportFragmentManager, + IAPDialogFragment.TAG + ) + viewModel.clearIAPState() + } + + IAPAction.ACTION_UNFULFILLED -> { + viewModel.detectUnfulfilledPurchase() + } + + IAPAction.ACTION_CLOSE -> { + viewModel.clearIAPState() + } + + IAPAction.ACTION_ERROR_CLOSE -> { + viewModel.logIAPCancelEvent() + } + + IAPAction.ACTION_GET_HELP -> { + iapException?.getFormattedErrorMessage() + ?.let { viewModel.showFeedbackScreen(requireActivity(), it) } + } + + else -> { + + } + } + } ) } } @@ -170,6 +235,7 @@ internal fun DashboardListView( apiHostUrl: String, state: DashboardUIState, uiMessage: UIMessage?, + iapUiState: IAPUIState?, canLoadMore: Boolean, refreshing: Boolean, hasInternetConnection: Boolean, @@ -177,6 +243,7 @@ internal fun DashboardListView( onSwipeRefresh: () -> Unit, paginationCallback: () -> Unit, onItemClick: (EnrolledCourse) -> Unit, + onIAPAction: (IAPAction, EnrolledCourse?, IAPException?) -> Unit, appUpgradeParameters: AppUpdateState.AppUpgradeParameters, ) { val scaffoldState = rememberScaffoldState() @@ -280,6 +347,19 @@ internal fun DashboardListView( course, windowSize, onClick = { onItemClick(it) }) + if (course.isUpgradeable && state.isValuePropEnabled) { + UpgradeToAccessView( + modifier = Modifier.padding( + bottom = 16.dp + ) + ) { + onIAPAction( + IAPAction.ACTION_USER_INITIATED, + course, + null + ) + } + } Divider() } item { @@ -299,6 +379,12 @@ internal fun DashboardListView( paginationCallback() } } + + LaunchedEffect(state.courses) { + if (state.courses.isNotEmpty()) { + onIAPAction(IAPAction.ACTION_UNFULFILLED, null, null) + } + } } is DashboardUIState.Empty -> { @@ -352,6 +438,41 @@ internal fun DashboardListView( ) } } + + when (iapUiState) { + is IAPUIState.PurchasesFulfillmentCompleted -> { + PurchasesFulfillmentCompletedDialog(onConfirm = { + onIAPAction(IAPAction.ACTION_COMPLETION, null, null) + }, onDismiss = { + onIAPAction(IAPAction.ACTION_CLOSE, null, null) + }) + } + + is IAPUIState.Error -> { + UpgradeErrorDialog( + title = stringResource(id = CoreR.string.iap_error_title), + description = stringResource(id = CoreR.string.iap_course_not_fullfilled), + confirmText = stringResource(id = CoreR.string.core_cancel), + onConfirm = { + onIAPAction( + IAPAction.ACTION_ERROR_CLOSE, + null, + null + ) + }, + dismissText = stringResource(id = CoreR.string.iap_get_help), + onDismiss = { + onIAPAction( + IAPAction.ACTION_GET_HELP, + null, + iapUiState.iapException + ) + } + ) + } + + else -> {} + } } } } @@ -524,23 +645,25 @@ private fun DashboardListViewPreview() { windowSize = WindowSize(WindowType.Compact, WindowType.Compact), apiHostUrl = "http://localhost:8000", state = DashboardUIState.Courses( - listOf( + courses = listOf( mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled - ) + ), isValuePropEnabled = false ), uiMessage = null, - onSwipeRefresh = {}, - onItemClick = {}, - onReloadClick = {}, - hasInternetConnection = true, - refreshing = false, + iapUiState = null, canLoadMore = false, + refreshing = false, + hasInternetConnection = true, + onReloadClick = {}, + onSwipeRefresh = {}, paginationCallback = {}, + onItemClick = {}, + onIAPAction = { _, _, _ -> }, appUpgradeParameters = AppUpdateState.AppUpgradeParameters() ) } @@ -555,23 +678,25 @@ private fun DashboardListViewTabletPreview() { windowSize = WindowSize(WindowType.Medium, WindowType.Medium), apiHostUrl = "http://localhost:8000", state = DashboardUIState.Courses( - listOf( + courses = listOf( mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled, mockCourseEnrolled - ) + ), isValuePropEnabled = false ), uiMessage = null, - onSwipeRefresh = {}, - onItemClick = {}, - onReloadClick = {}, - hasInternetConnection = true, - refreshing = false, + iapUiState = null, canLoadMore = false, + refreshing = false, + hasInternetConnection = true, + onReloadClick = {}, + onSwipeRefresh = {}, paginationCallback = {}, + onItemClick = {}, + onIAPAction = { _, _, _ -> }, appUpgradeParameters = AppUpdateState.AppUpgradeParameters() ) } @@ -596,7 +721,7 @@ private val mockCourseEnrolled = EnrolledCourse( startDisplay = "", startType = "", end = Date(), - dynamicUpgradeDeadline = "", + upgradeDeadline = "", subscriptionId = "", coursewareAccess = CoursewareAccess( true, @@ -615,5 +740,6 @@ private val mockCourseEnrolled = EnrolledCourse( discussionUrl = "", videoOutline = "", isSelfPaced = false - ) + ), + productInfo = ProductInfo(courseSku = "example_sku", storeSku = "mobile.android.example_100") ) diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt index bfafc81c4..a993a7291 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListViewModel.kt @@ -1,33 +1,63 @@ package org.openedx.dashboard.presentation +import android.content.Context import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.openedx.core.BaseViewModel import org.openedx.core.R import org.openedx.core.SingleEventLiveData import org.openedx.core.UIMessage import org.openedx.core.config.Config +import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.interactor.IAPInteractor import org.openedx.core.domain.model.EnrolledCourse +import org.openedx.core.exception.iap.IAPException import org.openedx.core.extension.isInternetError +import org.openedx.core.presentation.IAPAnalytics +import org.openedx.core.presentation.IAPAnalyticsEvent +import org.openedx.core.presentation.IAPAnalyticsKeys +import org.openedx.core.presentation.IAPAnalyticsScreen +import org.openedx.core.presentation.global.AppData +import org.openedx.core.presentation.iap.IAPAction +import org.openedx.core.presentation.iap.IAPFlow +import org.openedx.core.presentation.iap.IAPRequestType +import org.openedx.core.presentation.iap.IAPUIState import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection -import org.openedx.core.system.notifier.app.AppUpgradeEvent import org.openedx.core.system.notifier.CourseDashboardUpdate +import org.openedx.core.system.notifier.CourseDataUpdated import org.openedx.core.system.notifier.DiscoveryNotifier +import org.openedx.core.system.notifier.IAPNotifier +import org.openedx.core.system.notifier.UpdateCourseData import org.openedx.core.system.notifier.app.AppNotifier +import org.openedx.core.system.notifier.app.AppUpgradeEvent +import org.openedx.core.utils.EmailUtil import org.openedx.dashboard.domain.interactor.DashboardInteractor class DashboardListViewModel( + private val appData: AppData, private val config: Config, private val networkConnection: NetworkConnection, private val interactor: DashboardInteractor, private val resourceManager: ResourceManager, private val discoveryNotifier: DiscoveryNotifier, + private val iapNotifier: IAPNotifier, private val analytics: DashboardAnalytics, - private val appNotifier: AppNotifier + private val appNotifier: AppNotifier, + private val preferencesManager: CorePreferences, + private val iapAnalytics: IAPAnalytics, + private val iapInteractor: IAPInteractor ) : BaseViewModel() { private val coursesList = mutableListOf() @@ -44,6 +74,14 @@ class DashboardListViewModel( val uiMessage: LiveData get() = _uiMessage + private val _iapUiState = MutableSharedFlow( + replay = 0, + extraBufferCapacity = 1, + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) + val iapUiState: SharedFlow + get() = _iapUiState.asSharedFlow() + private val _updating = MutableLiveData() val updating: LiveData get() = _updating @@ -59,6 +97,12 @@ class DashboardListViewModel( val appUpgradeEvent: LiveData get() = _appUpgradeEvent + private val iapConfig + get() = preferencesManager.appConfig.iapConfig + private val isIAPEnabled + get() = iapConfig.isEnabled && + iapConfig.disableVersions.contains(appData.versionName).not() + override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) viewModelScope.launch { @@ -68,6 +112,14 @@ class DashboardListViewModel( } } } + + iapNotifier.notifier.onEach { event -> + when (event) { + is UpdateCourseData -> { + updateCourses(true) + } + } + }.distinctUntilChanged().launchIn(viewModelScope) } init { @@ -81,7 +133,7 @@ class DashboardListViewModel( internalLoadingCourses() } - fun updateCourses() { + fun updateCourses(isIAPFlow: Boolean = false) { if (isLoading) { return } @@ -103,7 +155,13 @@ class DashboardListViewModel( if (coursesList.isEmpty()) { _uiState.value = DashboardUIState.Empty } else { - _uiState.value = DashboardUIState.Courses(ArrayList(coursesList)) + _uiState.value = DashboardUIState.Courses( + courses = ArrayList(coursesList), + isValuePropEnabled = preferencesManager.appConfig.isValuePropEnabled + ) + } + if (isIAPFlow) { + iapNotifier.send(CourseDataUpdated()) } } catch (e: Exception) { if (e.isInternetError()) { @@ -146,7 +204,10 @@ class DashboardListViewModel( if (coursesList.isEmpty()) { _uiState.value = DashboardUIState.Empty } else { - _uiState.value = DashboardUIState.Courses(ArrayList(coursesList)) + _uiState.value = DashboardUIState.Courses( + courses = ArrayList(coursesList), + isValuePropEnabled = preferencesManager.appConfig.isValuePropEnabled + ) } } catch (e: Exception) { if (e.isInternetError()) { @@ -182,4 +243,75 @@ class DashboardListViewModel( analytics.dashboardCourseClickedEvent(courseId, courseName) } + fun detectUnfulfilledPurchase() { + if (isIAPEnabled) { + viewModelScope.launch(Dispatchers.IO) { + preferencesManager.user?.id?.let { userId -> + runCatching { + iapInteractor.processUnfulfilledPurchase(userId) + }.onSuccess { + if (it) { + unfulfilledPurchaseInitiatedEvent() + _iapUiState.emit(IAPUIState.PurchasesFulfillmentCompleted) + } + }.onFailure { + if (it is IAPException) { + _iapUiState.emit( + IAPUIState.Error( + IAPException( + IAPRequestType.UNFULFILLED_CODE, + it.httpErrorCode, + it.errorMessage + ) + ) + ) + } + } + } + } + } + } + + private fun unfulfilledPurchaseInitiatedEvent() { + logIAPEvent(IAPAnalyticsEvent.IAP_UNFULFILLED_PURCHASE_INITIATED) + } + + fun showFeedbackScreen(context: Context, message: String) { + EmailUtil.showFeedbackScreen( + context = context, + feedbackEmailAddress = config.getFeedbackEmailAddress(), + subject = context.getString(R.string.core_error_upgrading_course_in_app), + feedback = message, + appVersion = appData.versionName + ) + logIAPEvent(IAPAnalyticsEvent.IAP_ERROR_ALERT_ACTION, buildMap { + put(IAPAnalyticsKeys.ERROR_ALERT_TYPE.key, IAPAction.ACTION_UNFULFILLED.action) + put(IAPAnalyticsKeys.ERROR_ACTION.key, IAPAction.ACTION_GET_HELP.action) + }.toMutableMap()) + } + + fun logIAPCancelEvent() { + logIAPEvent(IAPAnalyticsEvent.IAP_ERROR_ALERT_ACTION, buildMap { + put(IAPAnalyticsKeys.ERROR_ALERT_TYPE.key, IAPAction.ACTION_UNFULFILLED.action) + put(IAPAnalyticsKeys.ERROR_ACTION.key, IAPAction.ACTION_CLOSE.action) + }.toMutableMap()) + } + + private fun logIAPEvent( + event: IAPAnalyticsEvent, + params: MutableMap = mutableMapOf() + ) { + iapAnalytics.logEvent(event.eventName, params.apply { + put(IAPAnalyticsKeys.NAME.key, event.biValue) + put(IAPAnalyticsKeys.SCREEN_NAME.key, IAPAnalyticsScreen.COURSE_ENROLLMENT.screenName) + put(IAPAnalyticsKeys.IAP_FLOW_TYPE.key, IAPFlow.SILENT.value) + put(IAPAnalyticsKeys.CATEGORY.key, IAPAnalyticsKeys.IN_APP_PURCHASES.key) + }) + } + + fun clearIAPState() { + viewModelScope.launch { + _iapUiState.emit(null) + } + } } diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardUIState.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardUIState.kt index 9f35594db..aa3ba1a31 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardUIState.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardUIState.kt @@ -3,7 +3,9 @@ package org.openedx.dashboard.presentation import org.openedx.core.domain.model.EnrolledCourse sealed class DashboardUIState { - data class Courses(val courses: List) : DashboardUIState() + data class Courses(val courses: List, val isValuePropEnabled: Boolean) : + DashboardUIState() + object Empty : DashboardUIState() object Loading : DashboardUIState() } diff --git a/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt b/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt index 2a1131392..e51468605 100644 --- a/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt +++ b/dashboard/src/test/java/org/openedx/dashboard/presentation/DashboardViewModelTest.kt @@ -27,12 +27,21 @@ import org.junit.rules.TestRule import org.openedx.core.R import org.openedx.core.UIMessage import org.openedx.core.config.Config +import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.interactor.IAPInteractor +import org.openedx.core.domain.model.AppConfig +import org.openedx.core.domain.model.CourseDatesCalendarSync import org.openedx.core.domain.model.DashboardCourseList +import org.openedx.core.domain.model.IAPConfig import org.openedx.core.domain.model.Pagination +import org.openedx.core.presentation.IAPAnalytics +import org.openedx.core.presentation.global.AppData import org.openedx.core.system.ResourceManager import org.openedx.core.system.connection.NetworkConnection import org.openedx.core.system.notifier.CourseDashboardUpdate +import org.openedx.core.system.notifier.CourseDataUpdated import org.openedx.core.system.notifier.DiscoveryNotifier +import org.openedx.core.system.notifier.IAPNotifier import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.dashboard.domain.interactor.DashboardInteractor import java.net.UnknownHostException @@ -48,10 +57,15 @@ class DashboardViewModelTest { private val config = mockk() private val resourceManager = mockk() private val interactor = mockk() + private val iapInteractor = mockk() private val networkConnection = mockk() private val discoveryNotifier = mockk() + private val iapNotifier = mockk() private val analytics = mockk() private val appNotifier = mockk() + private val iapAnalytics = mockk() + private val corePreferences = mockk() + private val appData = mockk() private val noInternet = "Slow or no internet connection" private val somethingWrong = "Something went wrong" @@ -61,6 +75,16 @@ class DashboardViewModelTest { listOf(mockk()) ) + private val appConfig = AppConfig( + courseDatesCalendarSync = CourseDatesCalendarSync( + isEnabled = true, + isSelfPacedEnabled = true, + isInstructorPacedEnabled = true, + isDeepLinkEnabled = false, + ), + iapConfig = IAPConfig(false, "prefix", listOf()) + ) + @Before fun setUp() { Dispatchers.setMain(dispatcher) @@ -77,16 +101,23 @@ class DashboardViewModelTest { @Test fun `getCourses no internet connection`() = runTest { + every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig } returns appConfig + val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) - every { networkConnection.isOnline() } returns true coEvery { interactor.getEnrolledCourses(any()) } throws UnknownHostException() advanceUntilIdle() @@ -101,16 +132,24 @@ class DashboardViewModelTest { @Test fun `getCourses unknown error`() = runTest { + every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig } returns appConfig + val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) - every { networkConnection.isOnline() } returns true + coEvery { interactor.getEnrolledCourses(any()) } throws Exception() advanceUntilIdle() @@ -125,16 +164,24 @@ class DashboardViewModelTest { @Test fun `getCourses from network`() = runTest { + every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig } returns appConfig + val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) - every { networkConnection.isOnline() } returns true + coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList coEvery { interactor.getEnrolledCoursesFromCache() } returns listOf(mockk()) advanceUntilIdle() @@ -149,16 +196,24 @@ class DashboardViewModelTest { @Test fun `getCourses from network with next page`() = runTest { + every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig } returns appConfig + val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) - every { networkConnection.isOnline() } returns true + coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList.copy( Pagination( 10, @@ -182,15 +237,23 @@ class DashboardViewModelTest { @Test fun `getCourses from cache`() = runTest { every { networkConnection.isOnline() } returns false + every { corePreferences.appConfig.isValuePropEnabled } returns false coEvery { interactor.getEnrolledCoursesFromCache() } returns listOf(mockk()) + every { corePreferences.appConfig.iapConfig } returns appConfig.iapConfig + val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) advanceUntilIdle() @@ -206,15 +269,21 @@ class DashboardViewModelTest { @Test fun `updateCourses no internet error`() = runTest { every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig } returns appConfig coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) coEvery { interactor.getEnrolledCourses(any()) } throws UnknownHostException() @@ -234,15 +303,21 @@ class DashboardViewModelTest { @Test fun `updateCourses unknown exception`() = runTest { every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig } returns appConfig coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) coEvery { interactor.getEnrolledCourses(any()) } throws Exception() @@ -262,15 +337,25 @@ class DashboardViewModelTest { @Test fun `updateCourses success`() = runTest { every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig.isValuePropEnabled } returns false + every { corePreferences.appConfig.iapConfig } returns appConfig.iapConfig coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList + coEvery { iapNotifier.notifier } returns flow { emit(CourseDataUpdated()) } + coEvery { iapNotifier.send(any()) } returns Unit + val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) viewModel.updateCourses() @@ -279,6 +364,7 @@ class DashboardViewModelTest { coVerify(exactly = 2) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } verify(exactly = 1) { appNotifier.notifier } + verify(exactly = 0) { iapNotifier.notifier } assert(viewModel.uiMessage.value == null) assert(viewModel.updating.value == false) @@ -288,6 +374,8 @@ class DashboardViewModelTest { @Test fun `updateCourses success with next page`() = runTest { every { networkConnection.isOnline() } returns true + every { corePreferences.appConfig.iapConfig } returns appConfig.iapConfig + every { corePreferences.appConfig.isValuePropEnabled } returns false coEvery { interactor.getEnrolledCourses(any()) } returns dashboardCourseList.copy( Pagination( 10, @@ -296,14 +384,22 @@ class DashboardViewModelTest { "" ) ) + coEvery { iapNotifier.notifier } returns flow { emit(CourseDataUpdated()) } + coEvery { iapNotifier.send(any()) } returns Unit + val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) viewModel.updateCourses() @@ -312,6 +408,7 @@ class DashboardViewModelTest { coVerify(exactly = 2) { interactor.getEnrolledCourses(any()) } coVerify(exactly = 0) { interactor.getEnrolledCoursesFromCache() } verify(exactly = 1) { appNotifier.notifier } + verify(exactly = 0) { iapNotifier.notifier } assert(viewModel.uiMessage.value == null) assert(viewModel.updating.value == false) @@ -321,14 +418,21 @@ class DashboardViewModelTest { @Test fun `CourseDashboardUpdate notifier test`() = runTest { coEvery { discoveryNotifier.notifier } returns flow { emit(CourseDashboardUpdate()) } + coEvery { iapNotifier.notifier } returns flow { emit(CourseDataUpdated()) } + every { corePreferences.appConfig } returns appConfig val viewModel = DashboardListViewModel( + appData, config, networkConnection, interactor, resourceManager, discoveryNotifier, + iapNotifier, analytics, - appNotifier + appNotifier, + corePreferences, + iapAnalytics, + iapInteractor ) val mockLifeCycleOwner: LifecycleOwner = mockk() @@ -340,6 +444,6 @@ class DashboardViewModelTest { coVerify(exactly = 1) { interactor.getEnrolledCourses(any()) } verify(exactly = 1) { appNotifier.notifier } + verify(exactly = 1) { iapNotifier.notifier } } - } diff --git a/default_config/dev/config.yaml b/default_config/dev/config.yaml index a97d7c351..56b8f2fe0 100644 --- a/default_config/dev/config.yaml +++ b/default_config/dev/config.yaml @@ -88,3 +88,5 @@ SOCIAL_AUTH_ENABLED: false UI_COMPONENTS: COURSE_DROPDOWN_NAVIGATION_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false + +ECOMMERCE_URL: 'http://localhost:8000' diff --git a/default_config/prod/config.yaml b/default_config/prod/config.yaml index a97d7c351..56b8f2fe0 100644 --- a/default_config/prod/config.yaml +++ b/default_config/prod/config.yaml @@ -88,3 +88,5 @@ SOCIAL_AUTH_ENABLED: false UI_COMPONENTS: COURSE_DROPDOWN_NAVIGATION_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false + +ECOMMERCE_URL: 'http://localhost:8000' diff --git a/default_config/stage/config.yaml b/default_config/stage/config.yaml index a97d7c351..56b8f2fe0 100644 --- a/default_config/stage/config.yaml +++ b/default_config/stage/config.yaml @@ -88,3 +88,5 @@ SOCIAL_AUTH_ENABLED: false UI_COMPONENTS: COURSE_DROPDOWN_NAVIGATION_ENABLED: false COURSE_UNIT_PROGRESS_ENABLED: false + +ECOMMERCE_URL: 'http://localhost:8000' diff --git a/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt b/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt index 9fc56f6af..cbd6d1386 100644 --- a/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt +++ b/discussion/src/test/java/org/openedx/discussion/presentation/topics/DiscussionTopicsViewModelTest.kt @@ -29,8 +29,10 @@ import org.openedx.core.UIMessage import org.openedx.core.domain.model.AssignmentProgress import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseAccessDetails import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess +import org.openedx.core.domain.model.EnrollmentDetails import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.CourseLoading import org.openedx.core.system.notifier.CourseNotifier @@ -130,18 +132,27 @@ class DiscussionTopicsViewModelTest { startDisplay = "", startType = "", end = Date(), - coursewareAccess = CoursewareAccess( - true, - "", - "", - "", - "", - "" - ), media = null, + courseAccessDetails = CourseAccessDetails( + Date(), coursewareAccess = CoursewareAccess( + true, + "", + "", + "", + "", + "" + ) + ), certificate = null, isSelfPaced = false, - progress = null + progress = null, + enrollmentDetails = EnrollmentDetails( + created = Date(), + mode = "audit", + isActive = false, + upgradeDeadline = Date() + ), + productInfo = null ) @Before @@ -160,7 +171,15 @@ class DiscussionTopicsViewModelTest { @Test fun `getCourseTopics no internet exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel( + "id", + "", + interactor, + resourceManager, + analytics, + courseNotifier, + router + ) coEvery { interactor.getCourseTopics(any()) } throws UnknownHostException() val message = async { @@ -177,7 +196,15 @@ class DiscussionTopicsViewModelTest { @Test fun `getCourseTopics unknown exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel( + "id", + "", + interactor, + resourceManager, + analytics, + courseNotifier, + router + ) coEvery { interactor.getCourseTopics(any()) } throws Exception() val message = async { @@ -194,7 +221,15 @@ class DiscussionTopicsViewModelTest { @Test fun `getCourseTopics success`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel( + "id", + "", + interactor, + resourceManager, + analytics, + courseNotifier, + router + ) coEvery { interactor.getCourseTopics(any()) } returns mockk() advanceUntilIdle() @@ -211,7 +246,15 @@ class DiscussionTopicsViewModelTest { @Test fun `updateCourseTopics no internet exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel( + "id", + "", + interactor, + resourceManager, + analytics, + courseNotifier, + router + ) coEvery { interactor.getCourseTopics(any()) } throws UnknownHostException() val message = async { @@ -228,7 +271,15 @@ class DiscussionTopicsViewModelTest { @Test fun `updateCourseTopics unknown exception`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel( + "id", + "", + interactor, + resourceManager, + analytics, + courseNotifier, + router + ) coEvery { interactor.getCourseTopics(any()) } throws Exception() val message = async { @@ -245,7 +296,15 @@ class DiscussionTopicsViewModelTest { @Test fun `updateCourseTopics success`() = runTest(UnconfinedTestDispatcher()) { - val viewModel = DiscussionTopicsViewModel("id", "", interactor, resourceManager, analytics, courseNotifier, router) + val viewModel = DiscussionTopicsViewModel( + "id", + "", + interactor, + resourceManager, + analytics, + courseNotifier, + router + ) coEvery { interactor.getCourseTopics(any()) } returns mockk() val message = async { @@ -260,5 +319,4 @@ class DiscussionTopicsViewModelTest { assert(message.await()?.message.isNullOrEmpty()) assert(viewModel.uiState.value is DiscussionTopicsUIState.Topics) } - } diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt index 7ac402330..7a3f3f7eb 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsFragment.kt @@ -10,6 +10,12 @@ import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.fragment.app.Fragment import org.koin.androidx.viewmodel.ext.android.viewModel +import org.openedx.core.presentation.IAPAnalyticsEvent +import org.openedx.core.presentation.IAPAnalyticsKeys +import org.openedx.core.presentation.IAPAnalyticsScreen +import org.openedx.core.presentation.dialog.IAPDialogFragment +import org.openedx.core.presentation.iap.IAPAction +import org.openedx.core.presentation.iap.IAPFlow import org.openedx.core.ui.rememberWindowSize import org.openedx.core.ui.theme.OpenEdXTheme @@ -27,12 +33,14 @@ class SettingsFragment : Fragment() { OpenEdXTheme { val windowSize = rememberWindowSize() val uiState by viewModel.uiState.collectAsState() + val iapUiState by viewModel.iapUiState.collectAsState() val logoutSuccess by viewModel.successLogout.collectAsState(false) val appUpgradeEvent by viewModel.appUpgradeEvent.collectAsState(null) SettingsScreen( windowSize = windowSize, uiState = uiState, + iapUiState = iapUiState, appUpgradeEvent = appUpgradeEvent, onBackClick = { requireActivity().supportFragmentManager.popBackStack() @@ -94,6 +102,48 @@ class SettingsFragment : Fragment() { requireActivity().supportFragmentManager ) } + + SettingsScreenAction.RestorePurchaseClick -> { + viewModel.restorePurchase() + } + } + }, + onIAPAction = { action, iapException -> + when (action) { + IAPAction.ACTION_ERROR_CLOSE -> { + viewModel.logIAPCancelEvent() + } + + IAPAction.ACTION_GET_HELP -> { + viewModel.clearIAPState() + val errorMessage = iapException?.getFormattedErrorMessage() ?: "" + viewModel.showFeedbackScreen(requireActivity(), errorMessage) + } + + IAPAction.ACTION_RESTORE -> { + IAPDialogFragment.newInstance( + IAPFlow.RESTORE, + IAPAnalyticsScreen.PROFILE.screenName + ).show( + requireActivity().supportFragmentManager, + IAPDialogFragment.TAG + ) + } + + IAPAction.ACTION_RESTORE_PURCHASE_CANCEL -> { + viewModel.logIAPEvent( + IAPAnalyticsEvent.IAP_ERROR_ALERT_ACTION, + buildMap { + put( + IAPAnalyticsKeys.ACTION.key, + IAPAction.ACTION_CLOSE.action + ) + }.toMutableMap() + ) + viewModel.clearIAPState() + } + + else -> {} } } ) @@ -120,5 +170,6 @@ internal interface SettingsScreenAction { object VideoSettingsClick : SettingsScreenAction object ManageAccountClick : SettingsScreenAction object CalendarSettingsClick : SettingsScreenAction + object RestorePurchaseClick : SettingsScreenAction } diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt index 5e044ca46..a2629ccb1 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsScreenUI.kt @@ -52,10 +52,17 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import org.openedx.core.R import org.openedx.core.domain.model.AgreementUrls +import org.openedx.core.exception.iap.IAPException import org.openedx.core.presentation.global.AppData +import org.openedx.core.presentation.iap.IAPAction +import org.openedx.core.presentation.iap.IAPLoaderType +import org.openedx.core.presentation.iap.IAPUIState import org.openedx.core.system.notifier.app.AppUpgradeEvent +import org.openedx.core.ui.CheckingPurchasesDialog +import org.openedx.core.ui.FakePurchasesFulfillmentCompleted import org.openedx.core.ui.OpenEdXButton import org.openedx.core.ui.Toolbar +import org.openedx.core.ui.UpgradeErrorDialog import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType import org.openedx.core.ui.displayCutoutForLandscape @@ -75,9 +82,11 @@ import org.openedx.profile.R as profileR internal fun SettingsScreen( windowSize: WindowSize, uiState: SettingsUIState, + iapUiState: IAPUIState?, appUpgradeEvent: AppUpgradeEvent?, onBackClick: () -> Unit, onAction: (SettingsScreenAction) -> Unit, + onIAPAction: (IAPAction, IAPException?) -> Unit, ) { var showLogoutDialog by rememberSaveable { mutableStateOf(false) } @@ -186,6 +195,12 @@ internal fun SettingsScreen( Spacer(modifier = Modifier.height(24.dp)) + PurchaseSection(onRestorePurchaseClick = { + onAction(SettingsScreenAction.RestorePurchaseClick) + }) + + Spacer(modifier = Modifier.height(24.dp)) + SupportInfoSection( uiState = uiState, onAction = onAction, @@ -206,6 +221,44 @@ internal fun SettingsScreen( } } } + + when (iapUiState) { + is IAPUIState.FakePurchasesFulfillmentCompleted -> { + FakePurchasesFulfillmentCompleted(onCancel = { + onIAPAction(IAPAction.ACTION_RESTORE_PURCHASE_CANCEL, null) + }, onGetHelp = { + onIAPAction(IAPAction.ACTION_GET_HELP, null) + }) + } + + is IAPUIState.Loading -> { + if (iapUiState.loaderType == IAPLoaderType.RESTORE_PURCHASES) { + CheckingPurchasesDialog() + } + } + + is IAPUIState.PurchasesFulfillmentCompleted -> { + onIAPAction(IAPAction.ACTION_RESTORE, null) + } + + is IAPUIState.Error -> { + UpgradeErrorDialog( + title = stringResource(id = R.string.iap_error_title), + description = stringResource(id = R.string.iap_course_not_fullfilled), + confirmText = stringResource(id = R.string.core_cancel), + onConfirm = { onIAPAction(IAPAction.ACTION_ERROR_CLOSE, null) }, + dismissText = stringResource(id = R.string.iap_get_help), + onDismiss = { + onIAPAction( + IAPAction.ACTION_GET_HELP, + iapUiState.iapException + ) + } + ) + } + + else -> {} + } } } @@ -243,6 +296,32 @@ private fun SettingsSection( } } +@Composable +private fun PurchaseSection(onRestorePurchaseClick: () -> Unit) { + Column { + Text( + modifier = Modifier.testTag("txt_purchases"), + text = stringResource(id = profileR.string.profile_purchases), + style = MaterialTheme.appTypography.labelLarge, + color = MaterialTheme.appColors.textSecondary + ) + Spacer(modifier = Modifier.height(14.dp)) + Card( + modifier = Modifier, + shape = MaterialTheme.appShapes.cardShape, + elevation = 0.dp, + backgroundColor = MaterialTheme.appColors.cardViewBackground + ) { + Column(Modifier.fillMaxWidth()) { + SettingsItem( + text = stringResource(id = profileR.string.profile_restore_purchaes), + onClick = onRestorePurchaseClick + ) + } + } + } +} + @Composable private fun ManageAccountSection(onManageAccountClick: () -> Unit) { Column { @@ -283,7 +362,7 @@ private fun SupportInfoSection( ) { Column(Modifier.fillMaxWidth()) { if (uiState.configuration.supportEmail.isNotBlank()) { - SettingsItem(text = stringResource(id = profileR.string.profile_contact_support)) { + SettingsItem(text = stringResource(id = R.string.core_contact_support)) { onAction(SettingsScreenAction.SupportClick) } SettingsDivider() @@ -687,11 +766,13 @@ private fun LogoutDialogPreview() { private fun SettingsScreenPreview() { OpenEdXTheme { SettingsScreen( - onBackClick = {}, windowSize = WindowSize(WindowType.Medium, WindowType.Medium), uiState = mockUiState, - onAction = {}, + iapUiState = null, appUpgradeEvent = null, + onBackClick = {}, + onAction = {}, + onIAPAction = { _, _ -> }, ) } } diff --git a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt index 6e622e2cc..305797cfd 100644 --- a/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt +++ b/profile/src/main/java/org/openedx/profile/presentation/settings/SettingsViewModel.kt @@ -5,6 +5,7 @@ import androidx.compose.ui.text.intl.Locale import androidx.fragment.app.FragmentManager import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow @@ -18,9 +19,20 @@ import org.openedx.core.BaseViewModel import org.openedx.core.R import org.openedx.core.UIMessage import org.openedx.core.config.Config +import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.interactor.IAPInteractor +import org.openedx.core.exception.iap.IAPException import org.openedx.core.extension.isInternetError import org.openedx.core.module.DownloadWorkerController +import org.openedx.core.presentation.IAPAnalyticsEvent +import org.openedx.core.presentation.IAPAnalyticsKeys +import org.openedx.core.presentation.IAPAnalyticsScreen import org.openedx.core.presentation.global.AppData +import org.openedx.core.presentation.iap.IAPAction +import org.openedx.core.presentation.iap.IAPFlow +import org.openedx.core.presentation.iap.IAPLoaderType +import org.openedx.core.presentation.iap.IAPRequestType +import org.openedx.core.presentation.iap.IAPUIState import org.openedx.core.system.AppCookieManager import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.app.AppNotifier @@ -40,7 +52,9 @@ class SettingsViewModel( private val appData: AppData, private val config: Config, private val resourceManager: ResourceManager, + private val corePreferences: CorePreferences, private val interactor: ProfileInteractor, + private val iapInteractor: IAPInteractor, private val cookieManager: AppCookieManager, private val workerController: DownloadWorkerController, private val analytics: ProfileAnalytics, @@ -49,9 +63,14 @@ class SettingsViewModel( private val profileNotifier: ProfileNotifier, ) : BaseViewModel() { - private val _uiState: MutableStateFlow = MutableStateFlow(SettingsUIState.Data(configuration)) + private val _uiState: MutableStateFlow = + MutableStateFlow(SettingsUIState.Data(configuration)) internal val uiState: StateFlow = _uiState.asStateFlow() + private val _iapUiState: MutableStateFlow = MutableStateFlow(null) + val iapUiState: StateFlow + get() = _iapUiState.asStateFlow() + private val _successLogout = MutableSharedFlow() val successLogout: SharedFlow get() = _successLogout.asSharedFlow() @@ -176,6 +195,7 @@ class SettingsViewModel( EmailUtil.showFeedbackScreen( context = context, feedbackEmailAddress = config.getFeedbackEmailAddress(), + subject = context.getString(R.string.core_error_upgrading_course_in_app), appVersion = appData.versionName ) logProfileEvent(ProfileAnalyticsEvent.CONTACT_SUPPORT_CLICKED) @@ -213,4 +233,83 @@ class SettingsViewModel( } ) } + + fun restorePurchase() { + logIAPEvent(IAPAnalyticsEvent.IAP_RESTORE_PURCHASE_CLICKED) + viewModelScope.launch(Dispatchers.IO) { + val userId = corePreferences.user?.id ?: return@launch + + _iapUiState.emit(IAPUIState.Loading(IAPLoaderType.RESTORE_PURCHASES)) + // delay to show loading state + delay(2000) + + runCatching { + iapInteractor.processUnfulfilledPurchase(userId) + }.onSuccess { + if (it) { + logIAPEvent(IAPAnalyticsEvent.IAP_UNFULFILLED_PURCHASE_INITIATED, buildMap { + put( + IAPAnalyticsKeys.SCREEN_NAME.key, + IAPAnalyticsScreen.PROFILE.screenName + ) + put(IAPAnalyticsKeys.IAP_FLOW_TYPE.key, IAPFlow.RESTORE.value) + }.toMutableMap()) + _iapUiState.emit(IAPUIState.PurchasesFulfillmentCompleted) + } else { + _iapUiState.emit(IAPUIState.FakePurchasesFulfillmentCompleted) + } + }.onFailure { + if (it is IAPException) { + _iapUiState.emit( + IAPUIState.Error( + IAPException( + IAPRequestType.RESTORE_CODE, + it.httpErrorCode, + it.errorMessage + ) + ) + ) + } + } + } + } + + fun logIAPCancelEvent() { + logIAPEvent(IAPAnalyticsEvent.IAP_ERROR_ALERT_ACTION, buildMap { + put(IAPAnalyticsKeys.ERROR_ALERT_TYPE.key, IAPAction.ACTION_RESTORE.action) + put(IAPAnalyticsKeys.ERROR_ACTION.key, IAPAction.ACTION_CLOSE.action) + }.toMutableMap()) + } + + fun showFeedbackScreen(context: Context, message: String) { + EmailUtil.showFeedbackScreen( + context = context, + feedbackEmailAddress = config.getFeedbackEmailAddress(), + subject = context.getString(R.string.core_error_upgrading_course_in_app), + feedback = message, + appVersion = appData.versionName + ) + logIAPEvent(IAPAnalyticsEvent.IAP_ERROR_ALERT_ACTION, buildMap { + put(IAPAnalyticsKeys.ERROR_ALERT_TYPE.key, IAPAction.ACTION_UNFULFILLED.action) + put(IAPAnalyticsKeys.ERROR_ACTION.key, IAPAction.ACTION_GET_HELP.action) + }.toMutableMap()) + } + + fun logIAPEvent( + event: IAPAnalyticsEvent, + params: MutableMap = mutableMapOf() + ) { + analytics.logEvent(event.eventName, params.apply { + put(IAPAnalyticsKeys.NAME.key, event.biValue) + put(IAPAnalyticsKeys.SCREEN_NAME.key, IAPAnalyticsScreen.PROFILE.screenName) + put(IAPAnalyticsKeys.IAP_FLOW_TYPE.key, IAPFlow.RESTORE.value) + put(IAPAnalyticsKeys.CATEGORY.key, IAPAnalyticsKeys.IN_APP_PURCHASES.key) + }) + } + + fun clearIAPState() { + viewModelScope.launch { + _iapUiState.emit(null) + } + } } diff --git a/profile/src/main/res/values/strings.xml b/profile/src/main/res/values/strings.xml index 60f0e4060..84cca0855 100644 --- a/profile/src/main/res/values/strings.xml +++ b/profile/src/main/res/values/strings.xml @@ -34,7 +34,6 @@ Changes you have made will be discarded. Log Out Are you sure you want to log out? - Contact Support Support Video Dates & Calendar @@ -60,5 +59,7 @@ Accent Course Dates Color + Purchases + Restore Purchases From 0ef101fbfae337d047f96cccd315939abfae9201 Mon Sep 17 00:00:00 2001 From: "omer.habib" Date: Fri, 12 Jul 2024 19:43:43 +0500 Subject: [PATCH 33/38] fix: Update course dates prefix on course cards - Update prefix according to legacy app - Remove lock icon from course card fix: LEARNER-10062 --- .../java/org/openedx/core/utils/TimeUtils.kt | 4 +-- core/src/main/res/values-uk/strings.xml | 6 ----- core/src/main/res/values/strings.xml | 11 ++++---- .../presentation/AllEnrolledCoursesView.kt | 25 ++++++++----------- .../presentation/DashboardGalleryView.kt | 25 ++++++++----------- 5 files changed, 29 insertions(+), 42 deletions(-) diff --git a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt index 5327b8cf5..fb0151c5c 100644 --- a/core/src/main/java/org/openedx/core/utils/TimeUtils.kt +++ b/core/src/main/java/org/openedx/core/utils/TimeUtils.kt @@ -116,12 +116,12 @@ object TimeUtils { DateUtils.SECOND_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE ).toString() - resourceManager.getString(R.string.core_label_expired, timeSpan) + resourceManager.getString(R.string.core_label_access_expired, timeSpan) } } else { formattedDate = if (dayDifferenceInMillis > SEVEN_DAYS_IN_MILLIS) { resourceManager.getString( - R.string.core_label_expires_on, + R.string.core_label_expires, dateToCourseDate(resourceManager, expiry) ) } else { diff --git a/core/src/main/res/values-uk/strings.xml b/core/src/main/res/values-uk/strings.xml index 2aab8871c..e232205bd 100644 --- a/core/src/main/res/values-uk/strings.xml +++ b/core/src/main/res/values-uk/strings.xml @@ -11,13 +11,7 @@ Скасувати Пошук Виберіть значення - Починається %1$s - Закінчився %1$s Закінчується %1$s - Термін дії курсу закінчується %1$s - Термін дії курсу закінчується %1$s - Термін дії курсу минув %1$s - Термін дії курсу минув %1$s Пароль незабаром Авто diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 931d2c6da..eb81f30d5 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -16,13 +16,12 @@ Cancel Search Select value - Starting %1$s - Ended %1$s + Starts %1$s + Ended on %1$s Ends %1$s - Course access expires %1$s - Course access expires on %1$s - Course access expired %1$s - Course access expired on %1$s + Access expires %1$s + Access expired %1$s + Expired on %1$s Password Soon Offline diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt index 3392ed7bd..2d21ba9ea 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/AllEnrolledCoursesView.kt @@ -452,17 +452,14 @@ fun CourseItem( overflow = TextOverflow.Ellipsis, minLines = 1, maxLines = 2, - text = stringResource( - org.openedx.dashboard.R.string.dashboard_course_date, - TimeUtils.getCourseFormattedDate( - LocalContext.current, - Date(), - course.auditAccessExpires, - course.course.start, - course.course.end, - course.course.startType, - course.course.startDisplay - ) + text = TimeUtils.getCourseFormattedDate( + LocalContext.current, + Date(), + course.auditAccessExpires, + course.course.start, + course.course.end, + course.course.startType, + course.course.startDisplay ) ) Text( @@ -476,9 +473,9 @@ fun CourseItem( maxLines = 2 ) } - if (!course.course.coursewareAccess?.errorCode.isNullOrEmpty()) { - Lock() - } +// if (!course.course.coursewareAccess?.errorCode.isNullOrEmpty()) { +// Lock() +// } } } } diff --git a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt index 7401f6304..48ca367fd 100644 --- a/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt +++ b/dashboard/src/main/java/org/openedx/courses/presentation/DashboardGalleryView.kt @@ -442,9 +442,9 @@ private fun CourseListItem( minLines = 2 ) } - if (!course.course.coursewareAccess?.errorCode.isNullOrEmpty()) { - Lock() - } +// if (!course.course.coursewareAccess?.errorCode.isNullOrEmpty()) { +// Lock() +// } } } } @@ -700,17 +700,14 @@ private fun PrimaryCourseTitle( modifier = Modifier.fillMaxWidth(), style = MaterialTheme.appTypography.labelMedium, color = MaterialTheme.appColors.textFieldHint, - text = stringResource( - R.string.dashboard_course_date, - TimeUtils.getCourseFormattedDate( - LocalContext.current, - Date(), - primaryCourse.auditAccessExpires, - primaryCourse.course.start, - primaryCourse.course.end, - primaryCourse.course.startType, - primaryCourse.course.startDisplay - ) + text = TimeUtils.getCourseFormattedDate( + LocalContext.current, + Date(), + primaryCourse.auditAccessExpires, + primaryCourse.course.start, + primaryCourse.course.end, + primaryCourse.course.startType, + primaryCourse.course.startDisplay ) ) } From 1f427dc8f86a4b9d9c31b87c258a2101da071a8a Mon Sep 17 00:00:00 2001 From: "omer.habib" Date: Fri, 28 Jun 2024 19:36:53 +0500 Subject: [PATCH 34/38] refactor: Improve customAppColors usage according to usage - refactor app design to efficiently handle customAppColor variables fix: LEARNER-10043 --- .../logistration/LogistrationFragment.kt | 6 +- .../presentation/signin/compose/SignInView.kt | 6 +- .../presentation/signup/compose/SignUpView.kt | 2 +- .../auth/presentation/ui/SocialAuthView.kt | 5 +- .../dialog/alert/ActionDialogFragment.kt | 17 ++-- .../dialog/alert/InfoDialogFragment.kt | 16 ++-- .../settings/video/VideoQualityFragment.kt | 10 ++- .../java/org/openedx/core/ui/ComposeCommon.kt | 22 ++--- core/src/main/res/values/themes.xml | 2 +- .../presentation/ChapterEndFragmentDialog.kt | 8 +- .../section/CourseSectionFragment.kt | 2 +- .../course/presentation/ui/CourseUI.kt | 18 ++-- .../unit/html/HtmlUnitFragment.kt | 4 +- .../presentation/AllEnrolledCoursesView.kt | 6 +- .../presentation/DashboardGalleryView.kt | 10 +-- .../presentation/DashboardListFragment.kt | 9 +- .../learn/presentation/LearnFragment.kt | 14 ++-- .../presentation/program/ProgramFragment.kt | 5 +- .../comments/DiscussionCommentsFragment.kt | 2 +- .../responses/DiscussionResponsesFragment.kt | 2 +- .../threads/DiscussionAddThreadFragment.kt | 6 +- .../threads/DiscussionThreadsFragment.kt | 2 +- .../presentation/ui/DiscussionUI.kt | 4 +- .../presentation/edit/EditProfileFragment.kt | 82 ++++++++++--------- .../compose/ManageAccountView.kt | 4 +- .../profile/compose/ProfileView.kt | 4 +- .../presentation/settings/SettingsScreenUI.kt | 2 + .../whatsnew/presentation/ui/WhatsNewUI.kt | 13 ++- 28 files changed, 154 insertions(+), 129 deletions(-) diff --git a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt index ae3d2365e..10539746b 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt @@ -135,7 +135,8 @@ private fun LogistrationScreen( style = MaterialTheme.appTypography.headlineSmall, modifier = Modifier .testTag("txt_screen_title") - .padding(bottom = 40.dp) + .padding(bottom = 40.dp), + color = MaterialTheme.appColors.textPrimary, ) val focusManager = LocalFocusManager.current Column(Modifier.padding(bottom = 8.dp)) { @@ -145,6 +146,7 @@ private fun LogistrationScreen( .padding(bottom = 10.dp), style = MaterialTheme.appTypography.titleMedium, text = stringResource(id = R.string.pre_auth_search_title), + color = MaterialTheme.appColors.textPrimary, ) SearchBar( modifier = Modifier @@ -176,7 +178,7 @@ private fun LogistrationScreen( onSearchClick("") }, text = stringResource(id = R.string.pre_auth_explore_all_courses), - color = MaterialTheme.appColors.primary, + color = MaterialTheme.appColors.textHyperLink, style = MaterialTheme.appTypography.labelLarge, textDecoration = TextDecoration.Underline ) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index cb77faa37..4b91aaa4f 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -272,7 +272,7 @@ private fun AuthForm( onEvent(AuthEvent.RegisterClick) }, text = stringResource(id = coreR.string.core_register), - color = MaterialTheme.appColors.primary, + color = MaterialTheme.appColors.textHyperLink, style = MaterialTheme.appTypography.labelLarge ) } @@ -284,7 +284,7 @@ private fun AuthForm( onEvent(AuthEvent.ForgotPasswordClick) }, text = stringResource(id = R.string.auth_forgot_password), - color = MaterialTheme.appColors.info_variant, + color = MaterialTheme.appColors.textHyperLink, style = MaterialTheme.appTypography.labelLarge ) } @@ -296,7 +296,7 @@ private fun AuthForm( modifier = buttonWidth.testTag("btn_sign_in"), text = stringResource(id = coreR.string.core_sign_in), textColor = MaterialTheme.appColors.primaryButtonText, - backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, + backgroundColor = MaterialTheme.appColors.primaryButtonBackground, onClick = { keyboardController?.hide() if (login.isNotEmpty() && password.isNotEmpty()) { diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt index e1e31c7b8..67cf30754 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt @@ -440,7 +440,7 @@ internal fun SignUpView( modifier = buttonWidth.testTag("btn_create_account"), text = stringResource(id = R.string.auth_create_account), textColor = MaterialTheme.appColors.primaryButtonText, - backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, + backgroundColor = MaterialTheme.appColors.primaryButtonBackground, onClick = { keyboardController?.hide() showErrorMap.clear() diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt index 028439290..c8ab3df16 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt @@ -40,13 +40,12 @@ internal fun SocialAuthView( } else { R.string.auth_continue_google } - OpenEdXOutlinedButton( + OpenEdXButton( modifier = Modifier .testTag("btn_google_auth") .padding(top = 24.dp) .fillMaxWidth(), backgroundColor = MaterialTheme.appColors.authGoogleButtonBackground, - borderColor = MaterialTheme.appColors.primary, textColor = Color.Unspecified, onClick = { onEvent(AuthType.GOOGLE) @@ -63,7 +62,7 @@ internal fun SocialAuthView( .testTag("txt_google_auth") .padding(start = 10.dp), text = stringResource(id = stringRes), - color = MaterialTheme.appColors.primaryButtonBorderedText, + color = MaterialTheme.appColors.textPrimaryLight, ) } } diff --git a/core/src/main/java/org/openedx/core/presentation/dialog/alert/ActionDialogFragment.kt b/core/src/main/java/org/openedx/core/presentation/dialog/alert/ActionDialogFragment.kt index b7b3167e6..6fba6836c 100644 --- a/core/src/main/java/org/openedx/core/presentation/dialog/alert/ActionDialogFragment.kt +++ b/core/src/main/java/org/openedx/core/presentation/dialog/alert/ActionDialogFragment.kt @@ -11,8 +11,10 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -170,6 +172,7 @@ private fun ActionDialog( text = stringResource(R.string.core_cancel), onClick = onPositiveClick ) + Spacer(modifier = Modifier.size(16.dp)) DefaultTextButton( text = stringResource(R.string.core_continue), onClick = onNegativeClick @@ -183,10 +186,12 @@ private fun ActionDialog( @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable private fun ActionDialogPreview() { - ActionDialog( - title = "Leaving the app", - message = "You are now leaving the app and opening a browser.", - onPositiveClick = {}, - onNegativeClick = {}, - ) + OpenEdXTheme { + ActionDialog( + title = "Leaving the app", + message = "You are now leaving the app and opening a browser.", + onPositiveClick = {}, + onNegativeClick = {}, + ) + } } diff --git a/core/src/main/java/org/openedx/core/presentation/dialog/alert/InfoDialogFragment.kt b/core/src/main/java/org/openedx/core/presentation/dialog/alert/InfoDialogFragment.kt index bc41d936d..0f6480316 100644 --- a/core/src/main/java/org/openedx/core/presentation/dialog/alert/InfoDialogFragment.kt +++ b/core/src/main/java/org/openedx/core/presentation/dialog/alert/InfoDialogFragment.kt @@ -1,5 +1,6 @@ package org.openedx.core.presentation.dialog.alert +import android.content.res.Configuration import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -116,12 +117,15 @@ private fun InfoDialog( } } -@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable private fun SimpleDialogPreview() { - InfoDialog( - title = "Important Notice", - message = "This is an important announcement.", - onClick = {} - ) + OpenEdXTheme { + InfoDialog( + title = "Important Notice", + message = "This is an important announcement.", + onClick = {} + ) + } } diff --git a/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityFragment.kt b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityFragment.kt index edd00ce53..fabc91513 100644 --- a/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityFragment.kt +++ b/core/src/main/java/org/openedx/core/presentation/settings/video/VideoQualityFragment.kt @@ -73,7 +73,7 @@ class VideoQualityFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ) = ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { @@ -125,7 +125,7 @@ private fun VideoQualityScreen( title: String, selectedVideoQuality: VideoQuality, onQualityChanged: (VideoQuality) -> Unit, - onBackClick: () -> Unit + onBackClick: () -> Unit, ) { val scaffoldState = rememberScaffoldState() Scaffold( @@ -136,6 +136,7 @@ private fun VideoQualityScreen( testTagsAsResourceId = true }, scaffoldState = scaffoldState, + backgroundColor = MaterialTheme.appColors.background ) { paddingValues -> val topBarWidth by remember(key1 = windowSize) { @@ -160,7 +161,8 @@ private fun VideoQualityScreen( } Box( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize(), contentAlignment = Alignment.TopCenter ) { Column( @@ -205,7 +207,7 @@ private fun QualityOption( title: String, description: String, selected: Boolean, - onClick: () -> Unit + onClick: () -> Unit, ) { Row( Modifier diff --git a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt index 735ca148a..2fa9d0855 100644 --- a/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt +++ b/core/src/main/java/org/openedx/core/ui/ComposeCommon.kt @@ -1,5 +1,6 @@ package org.openedx.core.ui +import android.content.res.Configuration import android.os.Build.VERSION.SDK_INT import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi @@ -202,7 +203,7 @@ fun Toolbar( ) { Icon( imageVector = Icons.Default.ManageAccounts, - tint = MaterialTheme.appColors.textAccent, + tint = MaterialTheme.appColors.primary, contentDescription = stringResource(id = R.string.core_accessibility_settings) ) } @@ -257,7 +258,7 @@ fun SearchBar( }, colors = TextFieldDefaults.outlinedTextFieldColors( textColor = MaterialTheme.appColors.textPrimary, - backgroundColor = if (isFocused) MaterialTheme.appColors.background else MaterialTheme.appColors.textFieldBackground, + backgroundColor = MaterialTheme.appColors.textFieldBackground, focusedBorderColor = MaterialTheme.appColors.primary, unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, cursorColor = MaterialTheme.appColors.primary, @@ -269,7 +270,7 @@ fun SearchBar( .testTag("txt_search_placeholder") .fillMaxWidth(), text = label, - color = MaterialTheme.appColors.textSecondary, + color = MaterialTheme.appColors.textFieldHint, style = MaterialTheme.appTypography.bodyMedium ) }, @@ -278,7 +279,7 @@ fun SearchBar( modifier = Modifier.padding(start = 16.dp), imageVector = Icons.Filled.Search, contentDescription = null, - tint = if (isFocused) MaterialTheme.appColors.primary else MaterialTheme.appColors.onSurface + tint = if (isFocused) MaterialTheme.appColors.textPrimary else MaterialTheme.appColors.textFieldHint ) }, trailingIcon = { @@ -1059,7 +1060,7 @@ fun OpenEdXButton( enabled: Boolean = true, textColor: Color = MaterialTheme.appColors.primaryButtonText, backgroundColor: Color = MaterialTheme.appColors.primaryButtonBackground, - content: (@Composable RowScope.() -> Unit)? = null + content: (@Composable RowScope.() -> Unit)? = null, ) { Button( modifier = Modifier @@ -1194,7 +1195,7 @@ fun AuthButtonsPanel( .weight(1f), text = stringResource(id = R.string.core_register), textColor = MaterialTheme.appColors.primaryButtonText, - backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, + backgroundColor = MaterialTheme.appColors.primaryButtonBackground, onClick = { onRegisterClick() } ) @@ -1221,7 +1222,7 @@ fun RoundTabsBar( contentPadding: PaddingValues = PaddingValues(), withPager: Boolean = false, rowState: LazyListState = rememberLazyListState(), - onTabClicked: (Int) -> Unit = { } + onTabClicked: (Int) -> Unit = { }, ) { // The pager state does not work without the pager and the tabs do not change. if (!withPager) { @@ -1249,7 +1250,7 @@ fun RoundTabsBar( RoundTab( modifier = Modifier - .height(40.dp) + .height(32.dp) .clip(CircleShape) .background(backgroundColor) .then(border) @@ -1272,7 +1273,7 @@ fun RoundTabsBar( private fun RoundTab( modifier: Modifier = Modifier, item: TabItem, - contentColor: Color + contentColor: Color, ) { Row( modifier = modifier, @@ -1380,7 +1381,8 @@ val mockTab = object : TabItem { } @OptIn(ExperimentalFoundationApi::class) -@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable private fun RoundTabsBarPreview() { OpenEdXTheme { diff --git a/core/src/main/res/values/themes.xml b/core/src/main/res/values/themes.xml index e6859e022..a092e8d47 100644 --- a/core/src/main/res/values/themes.xml +++ b/core/src/main/res/values/themes.xml @@ -12,7 +12,7 @@ ?attr/colorPrimaryVariant - @android:color/transparent + @color/background

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 literal 0 HcmV?d00001 diff --git a/core/src/edx/res/font/thin.ttf b/core/src/edx/res/font/thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fe77243fc7ae5f860243c768fc7bc659839988a5 GIT binary patch literal 310984 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