Explorar el Código

[new]完善首页开屏订阅流程

zk hace 1 año
padre
commit
9f9d87a9ff

+ 19 - 0
app/src/main/java/com/atmob/voiceai/data/api/bean/SplashPageBean.java

@@ -1,8 +1,12 @@
 package com.atmob.voiceai.data.api.bean;
 
+import com.atmob.common.text.TextUtil;
 import com.atmob.voiceai.sdk.billing.bean.GPProductInfo;
 import com.google.gson.annotations.SerializedName;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
 public class SplashPageBean {
     @SerializedName("id")
     private int id;
@@ -214,4 +218,19 @@ public class SplashPageBean {
     public void setRemark(String remark) {
         this.remark = remark;
     }
+
+    public String getPriceContent() {
+        if (content == null || content.isEmpty() || gpProductInfo == null) {
+            return content;
+        }
+        BigDecimal amountBigDecimal = new BigDecimal(gpProductInfo.getAmount()).divide(new BigDecimal(1000000), 2, RoundingMode.HALF_UP);
+        float goodsAmount = amountBigDecimal.floatValue();
+        String unit = "";
+        int unitIndex = gpProductInfo.getFormatPrice().indexOf(String.valueOf(goodsAmount));
+        if (unitIndex != -1) {
+            unit = gpProductInfo.getFormatPrice().substring(0, unitIndex);
+        }
+        String unPrice = unit + TextUtil.formatFloatWithout0End(goodsAmount / days, 2);
+        return content.replace("%s", unPrice);
+    }
 }

+ 16 - 0
app/src/main/java/com/atmob/voiceai/module/newsplash/NewSplashActivity.java

@@ -6,7 +6,9 @@ import androidx.annotation.Nullable;
 
 import com.atmob.app.lib.base.BaseActivity;
 import com.atmob.voiceai.databinding.ActivityNewSplashBinding;
+import com.atmob.voiceai.dialog.CommonLoadingDialog;
 import com.atmob.voiceai.module.main.MainActivity;
+import com.atmob.voiceai.utils.BoxingUtil;
 
 import dagger.hilt.android.AndroidEntryPoint;
 
@@ -16,6 +18,7 @@ public class NewSplashActivity extends BaseActivity<ActivityNewSplashBinding> {
 
 
     private NewSplashViewModel newSplashViewModel;
+    private CommonLoadingDialog loadingDialog;
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -26,11 +29,24 @@ public class NewSplashActivity extends BaseActivity<ActivityNewSplashBinding> {
 
     private void initObserver() {
         newSplashViewModel.getShowMainEvent().observe(this, o -> goMain());
+        newSplashViewModel.getShowLoading().observe(this, data -> showLoadingDialog(BoxingUtil.boxing(data.getFirst()), data.getSecond()));
     }
 
     private void initView() {
     }
 
+    public void showLoadingDialog(boolean show, String msg) {
+        if (show) {
+            if (loadingDialog == null) {
+                loadingDialog = new CommonLoadingDialog(this);
+            }
+            loadingDialog.setMessage(msg);
+            loadingDialog.show();
+        } else if (loadingDialog != null) {
+            loadingDialog.dismiss();
+        }
+    }
+
 
     @Override
     protected boolean shouldImmersion() {

+ 149 - 2
app/src/main/java/com/atmob/voiceai/module/newsplash/NewSplashViewModel.java

@@ -8,16 +8,25 @@ import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 
 import com.android.billingclient.api.BillingClient;
+import com.android.billingclient.api.BillingResult;
 import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.app.lib.handler.RxHttpHandler;
 import com.atmob.app.lib.livedata.SingleLiveEvent;
+import com.atmob.common.logging.AtmobLog;
+import com.atmob.common.runtime.ActivityUtil;
+import com.atmob.common.runtime.ContextUtil;
+import com.atmob.voiceai.R;
 import com.atmob.voiceai.data.api.bean.SplashPageBean;
+import com.atmob.voiceai.data.api.response.OrderPayResponse;
 import com.atmob.voiceai.data.api.response.SplashPageResponse;
 import com.atmob.voiceai.data.api.response.UserInfoResponse;
 import com.atmob.voiceai.data.consts.Constants;
 import com.atmob.voiceai.data.repositories.MemberRepository;
+import com.atmob.voiceai.helper.ErrorHelper;
 import com.atmob.voiceai.sdk.billing.GPBillingClient;
 import com.atmob.voiceai.utils.BoxingUtil;
 import com.atmob.voiceai.utils.CommonUtils;
+import com.atmob.voiceai.utils.ToastUtil;
 
 import java.util.concurrent.TimeUnit;
 
@@ -30,15 +39,18 @@ import atmob.reactivex.rxjava3.disposables.Disposable;
 import atmob.reactivex.rxjava3.schedulers.Schedulers;
 import atmob.rxjava.utils.RxJavaUtil;
 import dagger.hilt.android.lifecycle.HiltViewModel;
+import kotlin.Pair;
 
 
 @HiltViewModel
 public class NewSplashViewModel extends BaseViewModel {
 
+    private final String TAG = NewSplashViewModel.class.getSimpleName();
     private final SingleLiveEvent<?> showMainEvent = new SingleLiveEvent<>();
     private final MutableLiveData<Boolean> isShowRecommendPage = new MutableLiveData<>(false);
     private final MutableLiveData<SplashPageBean> splashGoods = new MutableLiveData<>();
     private final MutableLiveData<Boolean> isShowCloseBtn = new MutableLiveData<>();
+    private final SingleLiveEvent<Pair<Boolean, String>> showLoading = new SingleLiveEvent<>();
     private final MemberRepository memberRepository;
     private final GPBillingClient gpBillingClient;
     private long requestStartTime;
@@ -46,6 +58,7 @@ public class NewSplashViewModel extends BaseViewModel {
 
     private final long MAX_NET_REQUEST_TIME = 3000;
     private final long MAX_NET_ERROR_TIME = 8000;
+    private boolean isRequestSubmitOrder;
 
 
     @Inject
@@ -55,6 +68,14 @@ public class NewSplashViewModel extends BaseViewModel {
         refreshUserInfo();
     }
 
+    public LiveData<Pair<Boolean, String>> getShowLoading() {
+        return showLoading;
+    }
+
+    public LiveData<SplashPageBean> getSplashGoods() {
+        return splashGoods;
+    }
+
     public LiveData<Boolean> getIsShowCloseBtn() {
         return isShowCloseBtn;
     }
@@ -69,8 +90,11 @@ public class NewSplashViewModel extends BaseViewModel {
                 .timeout(MAX_NET_ERROR_TIME, TimeUnit.MILLISECONDS)
                 .onErrorReturn(throwable -> new UserInfoResponse())
                 .map(userInfoResponse -> {
-                    refreshSplashGoods();
-                    return userInfoResponse != null && userInfoResponse.getMemberInfo() != null && userInfoResponse.getMemberInfo().isIsMember();
+                    boolean isMember = userInfoResponse != null && userInfoResponse.getMemberInfo() != null && userInfoResponse.getMemberInfo().isIsMember();
+                    if (!isMember) {
+                        refreshSplashGoods();
+                    }
+                    return isMember;
                 })
                 .subscribe(new SingleObserver<Boolean>() {
                     @Override
@@ -101,6 +125,7 @@ public class NewSplashViewModel extends BaseViewModel {
 
 
     private void refreshSplashGoods() {
+        gpBillingClient.startUrgentConnection();
         memberRepository.requestSplashPage()
                 .map(SplashPageResponse::getItem)
                 .flatMap(splashPageBean ->
@@ -150,4 +175,126 @@ public class NewSplashViewModel extends BaseViewModel {
     public void onBackClick() {
         showMainEvent.call();
     }
+
+    public void onContinueClick() {
+        if (isRequestSubmitOrder) {
+            return;
+        }
+        SplashPageBean splashPageBean = splashGoods.getValue();
+        if (splashPageBean == null) {
+            return;
+        }
+        memberRepository.requestGoodsPayOrder(splashPageBean.getId(), 1, 4)
+                .subscribe(new SingleObserver<OrderPayResponse>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        addDisposable(d);
+                        isRequestSubmitOrder = true;
+                        showLoading.setValue(new Pair<>(true, null));
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull OrderPayResponse orderPayResponse) {
+                        isRequestSubmitOrder = false;
+                        showLoading.setValue(new Pair<>(false, null));
+                        requestPayment(splashPageBean, orderPayResponse.getOutTradeNo());
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+                        isRequestSubmitOrder = false;
+                        showLoading.setValue(new Pair<>(false, null));
+                        ErrorHelper.errorThrowableToast(e, ToastUtil.LENGTH_SHORT);
+                    }
+                });
+
+    }
+
+    private void requestPayment(SplashPageBean bean, String orderNo) {
+        gpBillingClient.launchPurchaseGoods(ActivityUtil.getTopActivity(),
+                        bean.getGpProductInfo().getProductDetails(), bean.getPlanId(), orderNo)
+                .compose(RxJavaUtil.SingleSchedule.subThread2Main())
+                .subscribe(new SingleObserver<BillingResult>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        addDisposable(d);
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull BillingResult billingResult) {
+                        AtmobLog.d(TAG, "requestPayment onSuccess: " + billingResult);
+                        gpBillingClient.registerFlowListener(this, orderNo, purchase -> queryOrderStatus(orderNo, purchase.getPurchaseToken()));
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+
+                    }
+                });
+    }
+
+    private void queryOrderStatus(String orderNo, String token) {
+        memberRepository.orderStatus(orderNo, token)
+                .subscribe(new SingleObserver<Boolean>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        addDisposable(d);
+                        addDisposable(RxJavaUtil.timer(25, TimeUnit.SECONDS, () -> {
+                            showLoading.setValue(new Pair<>(false, null));
+                            ToastUtil.show(R.string.query_order_time_out, ToastUtil.LENGTH_SHORT);
+                        }));
+                        showLoading.setValue(new Pair<>(true, ContextUtil.getContext().getString(R.string.query_order_status_loading_txt)));
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull Boolean aBoolean) {
+                        showLoading.setValue(new Pair<>(false, null));
+                        if (BoxingUtil.boxing(aBoolean)) {
+                            ToastUtil.show(R.string.pay_success, ToastUtil.LENGTH_SHORT);
+                            showMainEvent.call();
+                        }
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+                        showLoading.setValue(new Pair<>(false, null));
+                    }
+                });
+    }
+
+    public void onRestoreClick() {
+        memberRepository.subscriptionResume()
+                .subscribe(new SingleObserver<Object>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        addDisposable(d);
+                        showLoading.setValue(new Pair<>(true, ContextUtil.getContext().getString(R.string.query_order_status_loading_txt)));
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull Object object) {
+                        showLoading.setValue(new Pair<>(false, null));
+                        showMainEvent.call();
+                        ToastUtil.show(R.string.member_restore_success, ToastUtil.LENGTH_SHORT);
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+                        showLoading.setValue(new Pair<>(false, null));
+                        if (e instanceof RxHttpHandler.ServerErrorException) {
+                            RxHttpHandler.ServerErrorException serverErrorException = (RxHttpHandler.ServerErrorException) e;
+                            ToastUtil.show(serverErrorException.getMsg(), ToastUtil.LENGTH_SHORT);
+                        } else {
+                            ToastUtil.show(R.string.net_error_message, ToastUtil.LENGTH_SHORT);
+                        }
+                    }
+                });
+    }
+
+    @Override
+    protected void onCleared() {
+        super.onCleared();
+        gpBillingClient.endUrgentConnection();
+        gpBillingClient.unregisterAllFlowListener(this);
+    }
 }

+ 2 - 2
app/src/main/java/com/atmob/voiceai/sdk/billing/classify/QueryGoods.java

@@ -28,7 +28,7 @@ public class QueryGoods {
         if (FeatureSupported.isFeatureSupported(billingClient, BillingClient.FeatureType.PRODUCT_DETAILS)) {
             return queryProductDetails(billingClient, productType, productId, basePlanId);
         } else {
-            return querySkuDetails(billingClient, productType, productId, basePlanId, legacyProductId);
+            return querySkuDetails(billingClient, productType, productId, legacyProductId);
         }
     }
 
@@ -86,7 +86,7 @@ public class QueryGoods {
     }
 
 
-    private static Single<GPProductInfo> querySkuDetails(BillingClient billingClient, String productType, @NonNull String productId, @Nullable String basePlanId, @Nullable String legacyProductId) {
+    private static Single<GPProductInfo> querySkuDetails(BillingClient billingClient, String productType, @NonNull String productId, @Nullable String legacyProductId) {
         AtmobLog.i(TAG, "querySkuDetails() called with: productType = [" + productType + "], productId = [" + productId + "], legacyProductId = [" + legacyProductId + "]");
         SkuDetailsParams detailsParams = SkuDetailsParams.newBuilder()
                 .setSkusList(Collections.singletonList(!TextUtils.isEmpty(legacyProductId) ? legacyProductId : productId))

+ 9 - 4
app/src/main/res/layout/activity_new_splash.xml

@@ -72,12 +72,12 @@
                         app:layout_constraintTop_toBottomOf="@+id/space_status_bar" />
 
                     <ImageView
-                        android:onClick="@{()-> newSplashViewModel.onBackClick()}"
-                        isInvisible="@{!newSplashViewModel.isShowCloseBtn}"
                         android:id="@+id/iv_close"
+                        isInvisible="@{!newSplashViewModel.isShowCloseBtn}"
                         android:layout_width="0dp"
                         android:layout_height="0dp"
                         android:layout_marginStart="14dp"
+                        android:onClick="@{()-> newSplashViewModel.onBackClick()}"
                         android:src="@drawable/icon_new_splash_close"
                         app:layout_constraintDimensionRatio="1:1"
                         app:layout_constraintStart_toStartOf="parent"
@@ -169,6 +169,7 @@
                         android:id="@+id/tv_subscribe_price_desc"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
+                        android:text="@{newSplashViewModel.splashGoods.priceContent}"
                         android:textColor="@color/white"
                         android:textSize="20sp"
                         app:layout_constraintEnd_toEndOf="parent"
@@ -182,6 +183,8 @@
                         android:layout_height="wrap_content"
                         android:layout_marginTop="11dp"
                         android:drawablePadding="5.5dp"
+                        isGone="@{newSplashViewModel.splashGoods.remark.length() == 0}"
+                        android:text="@{newSplashViewModel.splashGoods.remark}"
                         android:textColor="#BEBFBE"
                         android:textSize="12sp"
                         app:drawableStartCompat="@drawable/icon_total_integration"
@@ -201,10 +204,10 @@
                 app:layout_constraintDimensionRatio="360:22" />
 
             <TextView
-                android:onClick="@{()-> newSplashViewModel.onTermsClick()}"
                 android:id="@+id/tv_terms_of_service"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:onClick="@{()-> newSplashViewModel.onTermsClick()}"
                 android:text="@string/setting_terms_of_service"
                 android:textColor="@color/white80"
                 android:textSize="12sp"
@@ -217,6 +220,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/sub_restore"
+                android:onClick="@{()-> newSplashViewModel.onRestoreClick()}"
                 android:textColor="@color/white80"
                 android:textSize="12sp"
                 app:layout_constraintBottom_toBottomOf="@+id/tv_terms_of_service"
@@ -225,10 +229,10 @@
                 app:layout_constraintTop_toTopOf="@+id/tv_terms_of_service" />
 
             <TextView
-                android:onClick="@{()-> newSplashViewModel.onPrivacyPolicyClick()}"
                 android:id="@+id/tv_privacy_policy"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:onClick="@{()-> newSplashViewModel.onPrivacyPolicyClick()}"
                 android:text="@string/setting_privacy_policy"
                 android:textColor="@color/white80"
                 android:textSize="12sp"
@@ -245,6 +249,7 @@
                 app:layout_constraintDimensionRatio="360:10" />
 
             <TextView
+                android:onClick="@{()-> newSplashViewModel.onContinueClick()}"
                 android:id="@+id/tv_continue"
                 android:layout_width="match_parent"
                 android:layout_height="0dp"