Skip to content

Commit

Permalink
fix: crash when restoring the app after a long period of inactivity
Browse files Browse the repository at this point in the history
  • Loading branch information
dixidroid committed May 6, 2024
1 parent 223fc43 commit 787ba1c
Show file tree
Hide file tree
Showing 16 changed files with 217 additions and 200 deletions.
2 changes: 1 addition & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ val screenModule = module {
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ 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(
private val api: CourseApi,
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<String, CourseStructure>()

suspend fun removeDownloadModel(id: String) {
downloadDao.removeDownloadModel(id)
Expand All @@ -26,35 +29,29 @@ 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()
}
suspend fun getCourseStructure(courseId: String): CourseStructure {
courseStructure[courseId]?.let { return it }

suspend fun preloadCourseStructureFromCache(courseId: String) {
val cachedCourseStructure = courseDao.getCourseStructureById(courseId)
courseStructure = null
if (cachedCourseStructure != null) {
courseStructure = cachedCourseStructure.mapToDomain()
} else {
throw NoCachedDataException()
}
}
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,10 @@ class CourseInteractor(
private val repository: CourseRepository
) {

suspend fun preloadCourseStructure(courseId: String) =
repository.preloadCourseStructure(courseId)
suspend fun getCourseStructure(courseId: String) = repository.getCourseStructure(courseId)

suspend fun preloadCourseStructureFromCache(courseId: String) =
repository.preloadCourseStructureFromCache(courseId)

@Throws(IllegalStateException::class)
fun getCourseStructureFromCache() = repository.getCourseStructureFromCache()

@Throws(IllegalStateException::class)
fun getCourseStructureForVideos(): CourseStructure {
val courseStructure = repository.getCourseStructureFromCache()
suspend fun getCourseStructureForVideos(courseId: String): CourseStructure {
val courseStructure = repository.getCourseStructure(courseId)
val blocks = courseStructure.blockData
val videoBlocks = blocks.filter { it.type == BlockType.VIDEO }
val resultBlocks = ArrayList<Block>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,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
Expand Down Expand Up @@ -248,7 +243,7 @@ class CourseContainerViewModel(
fun updateData() {
viewModelScope.launch {
try {
interactor.preloadCourseStructure(courseId)
interactor.getCourseStructure(courseId)
} catch (e: Exception) {
if (e.isInternetError()) {
_errorMessage.value =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -74,6 +75,7 @@ class CourseDatesViewModel(
_calendarSyncUIState.asStateFlow()

private var courseBannerType: CourseBannerType = CourseBannerType.BLANK
private var courseStructure: CourseStructure? = null

val isCourseExpandableSectionsEnabled get() = config.isCourseNestedListEnabled()

Expand Down Expand Up @@ -106,6 +108,7 @@ class CourseDatesViewModel(
private fun loadingCourseDatesInternal() {
viewModelScope.launch {
try {
courseStructure = interactor.getCourseStructure(courseId = courseId)
val datesResponse = interactor.getCourseDates(courseId = courseId)
if (datesResponse.datesSection.isEmpty()) {
_uiState.value = DatesUIState.Empty
Expand Down Expand Up @@ -146,18 +149,17 @@ 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
}
}

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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,28 @@ class CourseUnitContainerViewModel(
var hasNextBlock = false

private var currentMode: CourseViewMode? = null
private var currentComponentId = ""
private var courseName = ""

private val _descendantsBlocks = MutableStateFlow<List<Block>>(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()
}
}

Expand All @@ -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))
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class CourseVideoViewModel(

fun getVideos() {
viewModelScope.launch {
var courseStructure = interactor.getCourseStructureForVideos()
var courseStructure = interactor.getCourseStructureForVideos(courseId)
val blocks = courseStructure.blockData
if (blocks.isEmpty()) {
_uiState.value = CourseVideosUIState.Empty(
Expand Down
Loading

0 comments on commit 787ba1c

Please sign in to comment.