Skip to content
This repository has been archived by the owner on May 6, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1768 from openedx/farhan_ar/LEARNER-9312
Browse files Browse the repository at this point in the history
fix: Enrollment API call after purchase.
  • Loading branch information
farhan-arshad-dev authored Apr 1, 2023
2 parents 10aaf5c + f311e0d commit f512f6f
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.edx.mobile.event

/**
* The event to fire through [EventBus][org.greenrobot.eventbus.EventBus] whenever some screen state
* needs to refresh on [MyCoursesListFragment][org.edx.mobile.view.MyCoursesListFragment] after in-app
* purchase.
*/
class MyCoursesRefreshEvent
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,12 @@ class AppFeaturesPrefs @Inject constructor(@ApplicationContext context: Context)
}
return false
}

fun canAutoCheckUnfulfilledPurchase(): Boolean {
return pref.getBoolean(PrefManager.Key.CHECK_UNFULFILLED_PURCHASE, false)
}

fun setAutoCheckUnfulfilledPurchase(canCheckUnfulfilledPurchase: Boolean) {
pref.put(PrefManager.Key.CHECK_UNFULFILLED_PURCHASE, canCheckUnfulfilledPurchase)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ public static final class Key {
public static final String BULK_DOWNLOAD_FOR_COURSE_ID = "BULK_DOWNLOAD_%s";
// Preference to save app config
public static final String APP_CONFIG = "APP_CONFIG";
public static final String CHECK_UNFULFILLED_PURCHASE = "CHECK_UNFULFILLED_PURCHASE";
}

public static final class Value {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class CourseRepository @Inject constructor(
CoursesRequestType.STALE -> courseAPI.enrolledCourses
CoursesRequestType.CACHE -> courseAPI.enrolledCoursesFromCache
CoursesRequestType.LIVE -> courseAPI.enrolledCoursesWithoutStale
else -> throw java.lang.Exception("Unknown Request Type: $type")
}

call.enqueue(object : Callback<EnrollmentResponse> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import org.edx.mobile.deeplink.Screen
import org.edx.mobile.deeplink.ScreenDef
import org.edx.mobile.event.AccountDataLoadedEvent
import org.edx.mobile.event.IAPFlowEvent
import org.edx.mobile.event.MainDashboardRefreshEvent
import org.edx.mobile.event.MediaStatusChangeEvent
import org.edx.mobile.event.MyCoursesRefreshEvent
import org.edx.mobile.event.ProfilePhotoUpdatedEvent
import org.edx.mobile.exception.ErrorMessage
import org.edx.mobile.extenstion.isVisible
Expand Down Expand Up @@ -545,7 +545,7 @@ class AccountFragment : BaseFragment() {
@SuppressWarnings("unused")
fun onEventMainThread(event: IAPFlowEvent) {
if (this.isResumed && event.flowAction == IAPFlowData.IAPAction.PURCHASE_FLOW_COMPLETE) {
EventBus.getDefault().post(MainDashboardRefreshEvent())
EventBus.getDefault().post(MyCoursesRefreshEvent())
requireActivity().finish()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
import org.edx.mobile.event.CourseUpgradedEvent;
import org.edx.mobile.event.IAPFlowEvent;
import org.edx.mobile.event.LogoutEvent;
import org.edx.mobile.event.MainDashboardRefreshEvent;
import org.edx.mobile.event.MediaStatusChangeEvent;
import org.edx.mobile.event.MyCoursesRefreshEvent;
import org.edx.mobile.event.NetworkConnectivityChangeEvent;
import org.edx.mobile.exception.CourseContentNotValidException;
import org.edx.mobile.exception.ErrorMessage;
Expand Down Expand Up @@ -1061,7 +1061,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Update the User CourseEnrollments & Dates banner if after user
// Purchase course from Locked Component
courseDateViewModel.fetchCourseDatesBannerInfo(courseData.getCourseId(), true);
EventBus.getDefault().post(new MainDashboardRefreshEvent());
EventBus.getDefault().post(new MyCoursesRefreshEvent());
}
} else {
final CourseComponent outlineComp = courseManager.getComponentByIdFromAppLevelCache(
Expand Down Expand Up @@ -1138,7 +1138,7 @@ public void onEventMainThread(@NonNull IAPFlowEvent event) {
case PURCHASE_FLOW_COMPLETE: {
courseData.setMode(EnrollmentMode.VERIFIED.toString());
getCourseComponentFromServer(false, true);
EventBus.getDefault().post(new MainDashboardRefreshEvent());
EventBus.getDefault().post(new MyCoursesRefreshEvent());
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.edx.mobile.event.CourseUpgradedEvent;
import org.edx.mobile.event.FileSelectionEvent;
import org.edx.mobile.event.IAPFlowEvent;
import org.edx.mobile.event.MainDashboardRefreshEvent;
import org.edx.mobile.event.MyCoursesRefreshEvent;
import org.edx.mobile.event.VideoPlaybackEvent;
import org.edx.mobile.exception.ErrorMessage;
import org.edx.mobile.http.callback.ErrorHandlingCallback;
Expand Down Expand Up @@ -500,7 +500,7 @@ public void onEventMainThread(IAPFlowEvent event) {
break;
}
case PURCHASE_FLOW_COMPLETE: {
EventBus.getDefault().post(new MainDashboardRefreshEvent());
EventBus.getDefault().post(new MyCoursesRefreshEvent());
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import org.edx.mobile.event.EnrolledInCourseEvent
import org.edx.mobile.event.IAPFlowEvent
import org.edx.mobile.event.MainDashboardRefreshEvent
import org.edx.mobile.event.MoveToDiscoveryTabEvent
import org.edx.mobile.event.MyCoursesRefreshEvent
import org.edx.mobile.event.NetworkConnectivityChangeEvent
import org.edx.mobile.exception.ErrorMessage
import org.edx.mobile.extenstion.setVisibility
Expand Down Expand Up @@ -148,7 +149,17 @@ class MyCoursesListFragment : OfflineSupportBaseFragment(), RefreshListener {
environment.appFeaturesPrefs.isIAPEnabled(environment.loginPrefs.isOddUserId)
) {
initInAppPurchaseSetup()
detectUnfulfilledPurchase(enrolledCourses)
val fullscreenLoader = FullscreenLoaderDialogFragment.getRetainedInstance(
fragmentManager = childFragmentManager
)
if (fullscreenLoader != null) {
SnackbarErrorNotification(binding.root).showUpgradeSuccessSnackbar(R.string.purchase_success_message)
fullscreenLoader.closeLoader()
} else if (environment.appFeaturesPrefs.canAutoCheckUnfulfilledPurchase() &&
courseViewModel.courseRequestType != CoursesRequestType.CACHE
) {
detectUnfulfilledPurchase(enrolledCourses)
}
}
})

Expand Down Expand Up @@ -239,26 +250,18 @@ class MyCoursesListFragment : OfflineSupportBaseFragment(), RefreshListener {
}

/**
* Method to detect Unfulfilled Purchases if full screen loader is not visible.
* Method to detect Unfulfilled Purchases.
*
* @param enrolledCourses User enrolled courses.
* */
private fun detectUnfulfilledPurchase(enrolledCourses: List<EnrolledCoursesResponse>) {
val fullscreenLoader = FullscreenLoaderDialogFragment.getRetainedInstance(
fragmentManager = childFragmentManager
iapAnalytics.reset()
iapViewModel.detectUnfulfilledPurchase(
environment.loginPrefs.userId,
enrolledCourses,
IAPFlowData.IAPFlowType.SILENT,
Analytics.Screens.COURSE_ENROLLMENT
)
if (fullscreenLoader != null) {
SnackbarErrorNotification(binding.root).showUpgradeSuccessSnackbar(R.string.purchase_success_message)
fullscreenLoader.closeLoader()
} else {
iapAnalytics.reset()
iapViewModel.detectUnfulfilledPurchase(
environment.loginPrefs.userId,
enrolledCourses,
IAPFlowData.IAPFlowType.SILENT,
Analytics.Screens.COURSE_ENROLLMENT
)
}
}

override fun onResume() {
Expand Down Expand Up @@ -298,7 +301,7 @@ class MyCoursesListFragment : OfflineSupportBaseFragment(), RefreshListener {
}
}
IAPFlowData.IAPAction.PURCHASE_FLOW_COMPLETE -> {
onRefresh()
courseViewModel.fetchEnrolledCourses(type = CoursesRequestType.LIVE)
}
}
}
Expand Down Expand Up @@ -399,6 +402,12 @@ class MyCoursesListFragment : OfflineSupportBaseFragment(), RefreshListener {
courseViewModel.fetchEnrolledCourses(type = CoursesRequestType.LIVE)
}

@Subscribe(sticky = true)
@Suppress("UNUSED_PARAMETER")
fun onEvent(event: MyCoursesRefreshEvent) {
courseViewModel.fetchEnrolledCourses(type = CoursesRequestType.LIVE)
}

override fun onRevisit() {
super.onRevisit()
if (NetworkUtil.isConnected(activity)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ protected void onCreate(Bundle savedInstanceState) {
}

final IEdxEnvironment environment = MainApplication.getEnvironment(this);
environment.getAppFeaturesPrefs().setAutoCheckUnfulfilledPurchase(true);
if (environment.getLoginPrefs().isUserLoggedIn()) {
environment.getRouter().showMainDashboard(SplashActivity.this);
} else if (!environment.getConfig().isRegistrationEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class FullscreenLoaderDialogFragment : DialogFragment() {
initObservers()
if (iapFlowData?.isVerificationPending == true) {
iapViewModel.executeOrder(iapFlowData)
} else if (iapFlowData?.flowType?.isSilentMode() == true) {
} else {
purchaseFlowComplete()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ class CourseViewModel @Inject constructor(
private val _handleError = MutableLiveData<Throwable>()
val handleError: LiveData<Throwable> = _handleError

var courseRequestType: CoursesRequestType

init {
courseRequestType = CoursesRequestType.NONE
}

fun fetchEnrolledCourses(
type: CoursesRequestType,
showProgress: Boolean = true
Expand All @@ -52,6 +58,7 @@ class CourseViewModel @Inject constructor(

override fun onSuccess(result: Result.Success<EnrollmentResponse>) {
result.data?.let {
courseRequestType = type
_enrolledCourses.postEvent(it.enrollments)
environment.appFeaturesPrefs.setAppConfig(it.appConfig)

Expand Down Expand Up @@ -98,9 +105,15 @@ class CourseViewModel @Inject constructor(
}
}

override fun onCleared() {
super.onCleared()
courseRequestType = CoursesRequestType.NONE
}

sealed class CoursesRequestType {
object LIVE : CoursesRequestType()
object STALE : CoursesRequestType()
object CACHE : CoursesRequestType()
object NONE : CoursesRequestType()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel
import com.android.billingclient.api.Purchase
import com.android.billingclient.api.SkuDetails
import dagger.hilt.android.lifecycle.HiltViewModel
import org.edx.mobile.core.IEdxEnvironment
import org.edx.mobile.exception.ErrorMessage
import org.edx.mobile.extenstion.decodeToLong
import org.edx.mobile.http.model.NetworkResponseCallback
Expand All @@ -29,6 +30,7 @@ import javax.inject.Inject

@HiltViewModel
class InAppPurchasesViewModel @Inject constructor(
private val environment: IEdxEnvironment,
private val billingProcessor: BillingProcessor,
private val repository: InAppPurchasesRepository,
private val iapAnalytics: InAppPurchasesAnalytics
Expand Down Expand Up @@ -70,10 +72,12 @@ class InAppPurchasesViewModel @Inject constructor(

override fun onPurchaseComplete(purchase: Purchase) {
super.onPurchaseComplete(purchase)
iapFlowData.purchaseToken = purchase.purchaseToken
_productPurchased.postEvent(iapFlowData)
iapAnalytics.trackIAPEvent(eventName = Analytics.Events.IAP_PAYMENT_TIME)
iapAnalytics.initUnlockContentTime()
if (purchase.skus[0] == iapFlowData.productId) {
iapFlowData.purchaseToken = purchase.purchaseToken
_productPurchased.postEvent(iapFlowData)
iapAnalytics.trackIAPEvent(eventName = Analytics.Events.IAP_PAYMENT_TIME)
iapAnalytics.initUnlockContentTime()
}
}
}

Expand Down Expand Up @@ -218,6 +222,7 @@ class InAppPurchasesViewModel @Inject constructor(
return
}
billingProcessor.queryPurchase { _, purchases ->
environment.appFeaturesPrefs.setAutoCheckUnfulfilledPurchase(false)
if (purchases.isEmpty()) {
_fakeUnfulfilledCompletion.postEvent(true)
return@queryPurchase
Expand Down

0 comments on commit f512f6f

Please sign in to comment.