Skip to content

Commit

Permalink
Refactor AsyncResult into a sealed class.
Browse files Browse the repository at this point in the history
This also introduces an AsyncResultSubject, and more or less fully fixes
issue #3813 in all tests.

This is a cherry-pick from the fix-progress-controller-deadlock branch
since it ended up being quite large (it made more sense to split it into
a pre-requisite PR).

Conflicts:
	app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt
	domain/src/main/java/org/oppia/android/domain/exploration/ExplorationProgressController.kt
	domain/src/main/java/org/oppia/android/domain/question/QuestionAssessmentProgressController.kt
	domain/src/test/java/org/oppia/android/domain/exploration/lightweightcheckpointing/BUILD.bazel
	testing/src/main/java/org/oppia/android/testing/data/DataProviderTestMonitor.kt
	utility/src/main/java/org/oppia/android/util/data/DataProviders.kt
  • Loading branch information
BenHenning committed Mar 7, 2022
1 parent 36c4a5b commit 7cd0020
Show file tree
Hide file tree
Showing 111 changed files with 2,961 additions and 4,512 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ class AdministratorControlsViewModel @Inject constructor(
private fun processGetDeviceSettingsResult(
deviceSettingsResult: AsyncResult<DeviceSettings>
): DeviceSettings {
if (deviceSettingsResult.isFailure()) {
oppiaLogger.e(
"AdministratorControlsFragment",
"Failed to retrieve profile",
deviceSettingsResult.getErrorOrNull()!!
)
return when (deviceSettingsResult) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"AdministratorControlsFragment", "Failed to retrieve profile", deviceSettingsResult.error
)
DeviceSettings.getDefaultInstance()
}
is AsyncResult.Pending -> DeviceSettings.getDefaultInstance()
is AsyncResult.Success -> deviceSettingsResult.value
}
return deviceSettingsResult.getOrDefault(DeviceSettings.getDefaultInstance())
}

private fun processAdministratorControlsList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.oppia.android.app.model.DeviceSettings
import org.oppia.android.app.model.ProfileId
import org.oppia.android.domain.oppialogger.OppiaLogger
import org.oppia.android.domain.profile.ProfileManagementController
import org.oppia.android.util.data.AsyncResult
import org.oppia.android.util.data.DataProviders.Companion.toLiveData

/** [ViewModel] for the recycler view in [AdministratorControlsFragment]. */
Expand All @@ -31,11 +32,11 @@ class AdministratorControlsDownloadPermissionsViewModel(
.observe(
fragment,
Observer {
if (it.isFailure()) {
if (it is AsyncResult.Failure) {
oppiaLogger.e(
"AdministratorControlsFragment",
"Failed to update topic update on wifi permission",
it.getErrorOrNull()!!
it.error
)
}
}
Expand All @@ -49,11 +50,11 @@ class AdministratorControlsDownloadPermissionsViewModel(
).toLiveData().observe(
fragment,
Observer {
if (it.isFailure()) {
if (it is AsyncResult.Failure) {
oppiaLogger.e(
"AdministratorControlsFragment",
"Failed to update topic auto update permission",
it.getErrorOrNull()!!
it.error
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,18 @@ class CompletedStoryListViewModel @Inject constructor(
private fun processCompletedStoryListResult(
completedStoryListResult: AsyncResult<CompletedStoryList>
): CompletedStoryList {
if (completedStoryListResult.isFailure()) {
oppiaLogger.e(
"CompletedStoryListFragment",
"Failed to retrieve CompletedStory list: ",
completedStoryListResult.getErrorOrNull()!!
)
return when (completedStoryListResult) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"CompletedStoryListFragment",
"Failed to retrieve CompletedStory list: ",
completedStoryListResult.error
)
CompletedStoryList.getDefaultInstance()
}
is AsyncResult.Pending -> CompletedStoryList.getDefaultInstance()
is AsyncResult.Success -> completedStoryListResult.value
}
return completedStoryListResult.getOrDefault(CompletedStoryList.getDefaultInstance())
}

private fun processCompletedStoryList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ class MarkChaptersCompletedViewModel @Inject constructor(
private fun processStoryMapResult(
storyMap: AsyncResult<Map<String, List<StorySummary>>>
): Map<String, List<StorySummary>> {
if (storyMap.isFailure()) {
oppiaLogger.e(
"MarkChaptersCompletedFragment",
"Failed to retrieve storyList",
storyMap.getErrorOrNull()!!
)
return when (storyMap) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"MarkChaptersCompletedFragment", "Failed to retrieve storyList", storyMap.error
)
mapOf()
}
is AsyncResult.Pending -> mapOf()
is AsyncResult.Success -> storyMap.value
}
return storyMap.getOrDefault(mapOf())
}

private fun processStoryMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ class MarkStoriesCompletedViewModel @Inject constructor(
private fun processStoryMapResult(
storyMap: AsyncResult<Map<String, List<StorySummary>>>
): Map<String, List<StorySummary>> {
if (storyMap.isFailure()) {
oppiaLogger.e(
"MarkStoriesCompletedFragment",
"Failed to retrieve storyList",
storyMap.getErrorOrNull()!!
)
return when (storyMap) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"MarkStoriesCompletedFragment", "Failed to retrieve storyList", storyMap.error
)
mapOf()
}
is AsyncResult.Pending -> mapOf()
is AsyncResult.Success -> storyMap.value
}
return storyMap.getOrDefault(mapOf())
}

private fun processStoryMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,16 @@ class MarkTopicsCompletedViewModel @Inject constructor(
}

private fun processAllTopicsResult(allTopics: AsyncResult<List<Topic>>): List<Topic> {
if (allTopics.isFailure()) {
oppiaLogger.e(
"MarkTopicsCompletedFragment",
"Failed to retrieve all topics",
allTopics.getErrorOrNull()!!
)
return when (allTopics) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"MarkTopicsCompletedFragment", "Failed to retrieve all topics", allTopics.error
)
mutableListOf()
}
is AsyncResult.Pending -> mutableListOf()
is AsyncResult.Success -> allTopics.value
}
return allTopics.getOrDefault(mutableListOf())
}

private fun processAllTopics(allTopics: List<Topic>): List<TopicViewModel> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import android.view.ViewGroup
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.forEach
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData
Expand Down Expand Up @@ -41,6 +40,7 @@ import org.oppia.android.util.data.AsyncResult
import org.oppia.android.util.data.DataProviders.Companion.toLiveData
import org.oppia.android.util.statusbar.StatusBarColor
import javax.inject.Inject
import androidx.core.view.forEach

const val NAVIGATION_PROFILE_ID_ARGUMENT_KEY =
"NavigationDrawerFragmentPresenter.navigation_profile_id"
Expand Down Expand Up @@ -164,14 +164,14 @@ class NavigationDrawerFragmentPresenter @Inject constructor(
}

private fun processGetProfileResult(profileResult: AsyncResult<Profile>): Profile {
if (profileResult.isFailure()) {
oppiaLogger.e(
"NavigationDrawerFragment",
"Failed to retrieve profile",
profileResult.getErrorOrNull()!!
)
return when (profileResult) {
is AsyncResult.Failure -> {
oppiaLogger.e("NavigationDrawerFragment", "Failed to retrieve profile", profileResult.error)
Profile.getDefaultInstance()
}
is AsyncResult.Pending -> Profile.getDefaultInstance()
is AsyncResult.Success -> profileResult.value
}
return profileResult.getOrDefault(Profile.getDefaultInstance())
}

private fun getCompletedStoryListCount(): LiveData<CompletedStoryList> {
Expand All @@ -193,14 +193,18 @@ class NavigationDrawerFragmentPresenter @Inject constructor(
private fun processGetCompletedStoryListResult(
completedStoryListResult: AsyncResult<CompletedStoryList>
): CompletedStoryList {
if (completedStoryListResult.isFailure()) {
oppiaLogger.e(
"NavigationDrawerFragment",
"Failed to retrieve completed story list",
completedStoryListResult.getErrorOrNull()!!
)
return when (completedStoryListResult) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"NavigationDrawerFragment",
"Failed to retrieve completed story list",
completedStoryListResult.error
)
CompletedStoryList.getDefaultInstance()
}
is AsyncResult.Pending -> CompletedStoryList.getDefaultInstance()
is AsyncResult.Success -> completedStoryListResult.value
}
return completedStoryListResult.getOrDefault(CompletedStoryList.getDefaultInstance())
}

private fun getOngoingTopicListCount(): LiveData<OngoingTopicList> {
Expand All @@ -222,14 +226,18 @@ class NavigationDrawerFragmentPresenter @Inject constructor(
private fun processGetOngoingTopicListResult(
ongoingTopicListResult: AsyncResult<OngoingTopicList>
): OngoingTopicList {
if (ongoingTopicListResult.isFailure()) {
oppiaLogger.e(
"NavigationDrawerFragment",
"Failed to retrieve ongoing topic list",
ongoingTopicListResult.getErrorOrNull()!!
)
return when (ongoingTopicListResult) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"NavigationDrawerFragment",
"Failed to retrieve ongoing topic list",
ongoingTopicListResult.error
)
OngoingTopicList.getDefaultInstance()
}
is AsyncResult.Pending -> OngoingTopicList.getDefaultInstance()
is AsyncResult.Success -> ongoingTopicListResult.value
}
return ongoingTopicListResult.getOrDefault(OngoingTopicList.getDefaultInstance())
}

private fun openActivityByMenuItemId(menuItemId: Int) {
Expand Down
19 changes: 12 additions & 7 deletions app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.oppia.android.app.viewmodel.ObservableViewModel
import org.oppia.android.domain.oppialogger.OppiaLogger
import org.oppia.android.domain.profile.ProfileManagementController
import org.oppia.android.domain.topic.TopicListController
import org.oppia.android.util.data.AsyncResult
import org.oppia.android.util.data.DataProvider
import org.oppia.android.util.data.DataProviders.Companion.combineWith
import org.oppia.android.util.data.DataProviders.Companion.toLiveData
Expand Down Expand Up @@ -94,14 +95,18 @@ class HomeViewModel(
*/
val homeItemViewModelListLiveData: LiveData<List<HomeItemViewModel>> by lazy {
Transformations.map(homeItemViewModelListDataProvider.toLiveData()) { itemListResult ->
if (itemListResult.isFailure()) {
oppiaLogger.e(
"HomeFragment",
"No home fragment available -- failed to retrieve fragment data.",
itemListResult.getErrorOrNull()
)
return@map when (itemListResult) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"HomeFragment",
"No home fragment available -- failed to retrieve fragment data.",
itemListResult.error
)
listOf()
}
is AsyncResult.Pending -> listOf()
is AsyncResult.Success -> itemListResult.value
}
return@map itemListResult.getOrDefault(listOf())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,12 @@ class RecentlyPlayedFragmentPresenter @Inject constructor(
}

private fun getAssumedSuccessfulPromotedActivityList(): LiveData<PromotedActivityList> {
// If there's an error loading the data, assume the default.
return Transformations.map(ongoingStoryListSummaryResultLiveData) {
it.getOrDefault(
PromotedActivityList.getDefaultInstance()
)
when (it) {
// If there's an error loading the data, assume the default.
is AsyncResult.Failure, is AsyncResult.Pending -> PromotedActivityList.getDefaultInstance()
is AsyncResult.Success -> it.value
}
}
}

Expand Down Expand Up @@ -252,17 +253,17 @@ class RecentlyPlayedFragmentPresenter @Inject constructor(
fragment,
object : Observer<AsyncResult<ExplorationCheckpoint>> {
override fun onChanged(it: AsyncResult<ExplorationCheckpoint>) {
if (it.isSuccess()) {
if (it is AsyncResult.Success) {
explorationCheckpointLiveData.removeObserver(this)
routeToResumeLessonListener.routeToResumeLesson(
internalProfileId,
promotedStory.topicId,
promotedStory.storyId,
promotedStory.explorationId,
backflowScreen = null,
explorationCheckpoint = it.getOrThrow()
explorationCheckpoint = it.value
)
} else if (it.isFailure()) {
} else if (it is AsyncResult.Failure) {
explorationCheckpointLiveData.removeObserver(this)
playExploration(
promotedStory.topicId,
Expand Down Expand Up @@ -301,14 +302,11 @@ class RecentlyPlayedFragmentPresenter @Inject constructor(
).observe(
fragment,
Observer<AsyncResult<Any?>> { result ->
when {
result.isPending() -> oppiaLogger.d("RecentlyPlayedFragment", "Loading exploration")
result.isFailure() -> oppiaLogger.e(
"RecentlyPlayedFragment",
"Failed to load exploration",
result.getErrorOrNull()!!
)
else -> {
when (result) {
is AsyncResult.Pending -> oppiaLogger.d("RecentlyPlayedFragment", "Loading exploration")
is AsyncResult.Failure ->
oppiaLogger.e("RecentlyPlayedFragment", "Failed to load exploration", result.error)
is AsyncResult.Success -> {
oppiaLogger.d("RecentlyPlayedFragment", "Successfully loaded exploration")
routeToExplorationListener.routeToExploration(
internalProfileId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,18 @@ class OngoingTopicListViewModel @Inject constructor(
private fun processOngoingTopicResult(
ongoingTopicListResult: AsyncResult<OngoingTopicList>
): OngoingTopicList {
if (ongoingTopicListResult.isFailure()) {
oppiaLogger.e(
"OngoingTopicListFragment",
"Failed to retrieve OngoingTopicList: ",
ongoingTopicListResult.getErrorOrNull()!!
)
return when (ongoingTopicListResult) {
is AsyncResult.Failure -> {
oppiaLogger.e(
"OngoingTopicListFragment",
"Failed to retrieve OngoingTopicList: ",
ongoingTopicListResult.error
)
OngoingTopicList.getDefaultInstance()
}
is AsyncResult.Pending -> OngoingTopicList.getDefaultInstance()
is AsyncResult.Success -> ongoingTopicListResult.value
}
return ongoingTopicListResult.getOrDefault(OngoingTopicList.getDefaultInstance())
}

private fun processOngoingTopicList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,14 @@ class OptionControlsViewModel @Inject constructor(
}

private fun processProfileResult(profile: AsyncResult<Profile>): Profile {
if (profile.isFailure()) {
oppiaLogger.e("OptionsFragment", "Failed to retrieve profile", profile.getErrorOrNull()!!)
return when (profile) {
is AsyncResult.Failure -> {
oppiaLogger.e("OptionsFragment", "Failed to retrieve profile", profile.error)
Profile.getDefaultInstance()
}
is AsyncResult.Pending -> Profile.getDefaultInstance()
is AsyncResult.Success -> profile.value
}
return profile.getOrDefault(Profile.getDefaultInstance())
}

private fun processProfileList(profile: Profile): List<OptionsItemViewModel> {
Expand Down
Loading

0 comments on commit 7cd0020

Please sign in to comment.