Browse Source

增加支付界面

zk 1 year ago
parent
commit
f542af3035
93 changed files with 3654 additions and 36 deletions
  1. 3 0
      app/build.gradle
  2. 20 11
      app/src/main/AndroidManifest.xml
  3. 19 0
      app/src/main/java/com/datarecovery/master/data/api/AtmobApi.java
  4. 91 0
      app/src/main/java/com/datarecovery/master/data/api/bean/MemberGoodsBean.java
  5. 62 0
      app/src/main/java/com/datarecovery/master/data/api/bean/PayOptionsBean.java
  6. 54 0
      app/src/main/java/com/datarecovery/master/data/api/bean/WechatPaymentSignBean.java
  7. 13 0
      app/src/main/java/com/datarecovery/master/data/api/request/FindOrderRequest.java
  8. 14 0
      app/src/main/java/com/datarecovery/master/data/api/request/MemberDetailRequest.java
  9. 21 0
      app/src/main/java/com/datarecovery/master/data/api/request/MemberPayRequest.java
  10. 12 0
      app/src/main/java/com/datarecovery/master/data/api/request/PaymentStatusRequest.java
  11. 40 0
      app/src/main/java/com/datarecovery/master/data/api/response/FindOrderResponse.java
  12. 31 0
      app/src/main/java/com/datarecovery/master/data/api/response/MemberDetailResponse.java
  13. 56 0
      app/src/main/java/com/datarecovery/master/data/api/response/MemberPayResponse.java
  14. 13 0
      app/src/main/java/com/datarecovery/master/data/api/response/PaymentStatusResponse.java
  15. 3 3
      app/src/main/java/com/datarecovery/master/data/consts/Constants.java
  16. 1 1
      app/src/main/java/com/datarecovery/master/data/consts/ErrorCode.java
  17. 75 0
      app/src/main/java/com/datarecovery/master/data/repositories/MemberRepository.java
  18. 10 0
      app/src/main/java/com/datarecovery/master/data/repositories/PayRepository.java
  19. 68 0
      app/src/main/java/com/datarecovery/master/dialog/AlipayQrCodeDialog.java
  20. 93 0
      app/src/main/java/com/datarecovery/master/dialog/ChoosePaymentWayDialog.java
  21. 43 0
      app/src/main/java/com/datarecovery/master/dialog/MemberRetentionDialog.java
  22. 60 0
      app/src/main/java/com/datarecovery/master/dialog/WechatPayQrCodeDialog.java
  23. 3 1
      app/src/main/java/com/datarecovery/master/module/homepage/HomePageViewModel.java
  24. 121 0
      app/src/main/java/com/datarecovery/master/module/member/GoodsItemAdapter.java
  25. 227 0
      app/src/main/java/com/datarecovery/master/module/member/MemberActivity.java
  26. 72 0
      app/src/main/java/com/datarecovery/master/module/member/MemberEvaluateAdapter.java
  27. 30 0
      app/src/main/java/com/datarecovery/master/module/member/MemberType.java
  28. 381 0
      app/src/main/java/com/datarecovery/master/module/member/MemberViewModel.java
  29. 57 0
      app/src/main/java/com/datarecovery/master/module/member/NormalScenesAdapter.java
  30. 57 0
      app/src/main/java/com/datarecovery/master/module/member/SuperScenesAdapter.java
  31. 44 0
      app/src/main/java/com/datarecovery/master/module/member/bean/EvaluateBean.java
  32. 31 0
      app/src/main/java/com/datarecovery/master/module/member/bean/SuperScenesBean.java
  33. 1 1
      app/src/main/java/com/datarecovery/master/module/order/OrderViewModel.java
  34. 62 0
      app/src/main/java/com/datarecovery/master/module/wxrecover/WeChatRecoverActivity.java
  35. 78 0
      app/src/main/java/com/datarecovery/master/module/wxrecover/WeChatViewModel.java
  36. 23 0
      app/src/main/java/com/datarecovery/master/utils/ClipboardUtil.java
  37. 63 0
      app/src/main/java/com/datarecovery/master/utils/GridLayoutItemDecoration.java
  38. 0 16
      app/src/main/java/com/datarecovery/master/utils/GridRecoverItemDecoration.java
  39. 101 0
      app/src/main/java/com/datarecovery/master/utils/QrCodeUtil.java
  40. 28 0
      app/src/main/java/com/datarecovery/master/widget/UntouchableWebView.java
  41. BIN
      app/src/main/res/drawable-xxhdpi/bg_member_goods_type_normal.webp
  42. BIN
      app/src/main/res/drawable-xxhdpi/bg_member_goods_type_selected.webp
  43. BIN
      app/src/main/res/drawable-xxhdpi/bg_member_header_img.webp
  44. BIN
      app/src/main/res/drawable-xxhdpi/bg_splash.webp
  45. BIN
      app/src/main/res/drawable-xxhdpi/icon_alipay_payment.webp
  46. BIN
      app/src/main/res/drawable-xxhdpi/icon_alipay_scan_payment.webp
  47. BIN
      app/src/main/res/drawable-xxhdpi/icon_evaluate_1.webp
  48. BIN
      app/src/main/res/drawable-xxhdpi/icon_evaluate_2.webp
  49. BIN
      app/src/main/res/drawable-xxhdpi/icon_evaluate_3.webp
  50. BIN
      app/src/main/res/drawable-xxhdpi/icon_hot.webp
  51. BIN
      app/src/main/res/drawable-xxhdpi/icon_member_back.webp
  52. BIN
      app/src/main/res/drawable-xxhdpi/icon_member_close.webp
  53. BIN
      app/src/main/res/drawable-xxhdpi/icon_member_retention_header.webp
  54. BIN
      app/src/main/res/drawable-xxhdpi/icon_scenes_1.webp
  55. BIN
      app/src/main/res/drawable-xxhdpi/icon_scenes_2.webp
  56. BIN
      app/src/main/res/drawable-xxhdpi/icon_scenes_3.webp
  57. BIN
      app/src/main/res/drawable-xxhdpi/icon_scenes_4.webp
  58. BIN
      app/src/main/res/drawable-xxhdpi/icon_scenes_5.webp
  59. BIN
      app/src/main/res/drawable-xxhdpi/icon_scenes_6.webp
  60. BIN
      app/src/main/res/drawable-xxhdpi/icon_scenes_7.webp
  61. BIN
      app/src/main/res/drawable-xxhdpi/icon_star.webp
  62. BIN
      app/src/main/res/drawable-xxhdpi/icon_wechat_payment.webp
  63. BIN
      app/src/main/res/drawable-xxhdpi/icon_wechat_scan_payment.webp
  64. BIN
      app/src/main/res/drawable-xxhdpi/icon_wx_recover_pay_success.webp
  65. 8 0
      app/src/main/res/drawable/bg_choice_payment_pay.xml
  66. 8 0
      app/src/main/res/drawable/bg_dialog_member_retention.xml
  67. 7 0
      app/src/main/res/drawable/bg_member_bottom.xml
  68. 12 0
      app/src/main/res/drawable/bg_member_buy_btn.xml
  69. 7 0
      app/src/main/res/drawable/bg_member_container.xml
  70. 11 0
      app/src/main/res/drawable/bg_member_tag.xml
  71. 10 0
      app/src/main/res/drawable/bg_member_title.xml
  72. 6 0
      app/src/main/res/drawable/bg_payment_qr_code.xml
  73. 5 0
      app/src/main/res/drawable/bg_scenes_circle.xml
  74. 5 0
      app/src/main/res/drawable/bg_scenes_container.xml
  75. 5 0
      app/src/main/res/drawable/bg_wx_recover.xml
  76. 5 0
      app/src/main/res/drawable/bg_wx_recover_copy.xml
  77. 5 0
      app/src/main/res/drawable/bg_wx_recover_desc.xml
  78. 286 0
      app/src/main/res/layout/activity_member.xml
  79. 297 0
      app/src/main/res/layout/activity_wx_recover.xml
  80. 67 0
      app/src/main/res/layout/dialog_alipay_qr_code.xml
  81. 109 0
      app/src/main/res/layout/dialog_choose_payment_way.xml
  82. 110 0
      app/src/main/res/layout/dialog_member_retention.xml
  83. 66 0
      app/src/main/res/layout/dialog_wechat_pay_qr_code.xml
  84. 2 2
      app/src/main/res/layout/fragment_example.xml
  85. 1 1
      app/src/main/res/layout/fragment_order.xml
  86. 85 0
      app/src/main/res/layout/item_member_evaluate.xml
  87. 132 0
      app/src/main/res/layout/item_member_goods.xml
  88. 23 0
      app/src/main/res/layout/item_normal_scenes.xml
  89. 63 0
      app/src/main/res/layout/item_super_scenes.xml
  90. 84 0
      app/src/main/res/layout/layout_item_payment_way.xml
  91. 4 0
      app/src/main/res/values/colors.xml
  92. 38 0
      app/src/main/res/values/strings.xml
  93. 12 0
      app/src/main/res/values/themes.xml

+ 3 - 0
app/build.gradle

@@ -161,6 +161,9 @@ dependencies {
     //PhotoView
     implementation 'com.github.chrisbanes:PhotoView:2.3.0'
 
+    //zxing
+    implementation "third.zxing:zxing:3.5.1"
+
     //引力引擎
     implementation "cn.gravity.android:GravityEngineSDK:4.6.3"
 

+ 20 - 11
app/src/main/AndroidManifest.xml

@@ -28,6 +28,21 @@
         tools:targetApi="32">
 
         <activity
+            android:name=".module.wechat.WechatEntryActivity"
+            android:exported="true"
+            android:launchMode="singleTask"
+
+            android:screenOrientation="portrait"
+            android:taskAffinity="${applicationId}"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+
+        <activity-alias
+            android:name="${applicationId}.wxapi.WXEntryActivity"
+            android:exported="true"
+            android:targetActivity=".module.wechat.WechatEntryActivity" />
+
+        <activity
             android:name=".module.splash.SplashActivity"
             android:exported="true"
             android:screenOrientation="portrait"
@@ -69,20 +84,14 @@
             android:name=".module.audiorecover.AudioRecoverActivity"
             android:screenOrientation="portrait" />
 
-
         <activity
-            android:name=".module.wechat.WechatEntryActivity"
-            android:exported="true"
-            android:launchMode="singleTask"
+            android:name=".module.member.MemberActivity"
+            android:screenOrientation="portrait" />
+        <activity
+            android:name=".module.wxrecover.WeChatRecoverActivity"
+            android:screenOrientation="portrait" />
 
-            android:screenOrientation="portrait"
-            android:taskAffinity="${applicationId}"
-            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
 
-        <activity-alias
-            android:name="${applicationId}.wxapi.WXEntryActivity"
-            android:exported="true"
-            android:targetActivity=".module.wechat.WechatEntryActivity" />
     </application>
 
 </manifest>

+ 19 - 0
app/src/main/java/com/datarecovery/master/data/api/AtmobApi.java

@@ -3,12 +3,20 @@ package com.datarecovery.master.data.api;
 
 import com.atmob.app.lib.base.BaseResponse;
 import com.datarecovery.master.data.api.request.BaseRequest;
+import com.datarecovery.master.data.api.request.FindOrderRequest;
 import com.datarecovery.master.data.api.request.LoginRequest;
+import com.datarecovery.master.data.api.request.MemberDetailRequest;
+import com.datarecovery.master.data.api.request.MemberPayRequest;
 import com.datarecovery.master.data.api.request.OrderPageRequest;
+import com.datarecovery.master.data.api.request.PaymentStatusRequest;
 import com.datarecovery.master.data.api.request.SendCodeRequest;
+import com.datarecovery.master.data.api.response.FindOrderResponse;
 import com.datarecovery.master.data.api.response.FuncAuthsResponse;
 import com.datarecovery.master.data.api.response.LoginResponse;
+import com.datarecovery.master.data.api.response.MemberDetailResponse;
+import com.datarecovery.master.data.api.response.MemberPayResponse;
 import com.datarecovery.master.data.api.response.OrderPageResponse;
+import com.datarecovery.master.data.api.response.PaymentStatusResponse;
 
 import atmob.reactivex.rxjava3.core.Single;
 import atmob.retrofit2.http.Body;
@@ -29,4 +37,15 @@ public interface AtmobApi {
     @POST("/project/recover/v1/func/auths")
     Single<BaseResponse<FuncAuthsResponse>> funcAuths(@Body BaseRequest request);
 
+    @POST("/project/recover/v1/item/list")
+    Single<BaseResponse<MemberDetailResponse>> memberDetail(@Body MemberDetailRequest request);
+
+    @POST("/project/recover/v1/order/pay")
+    Single<BaseResponse<MemberPayResponse>> requestPayOrder(@Body MemberPayRequest request);
+
+    @POST("/project/recover/v1/order/status")
+    Single<BaseResponse<PaymentStatusResponse>> getPayStatus(@Body PaymentStatusRequest request);
+
+    @POST("/project/recover/v1/order/find")
+    Single<BaseResponse<FindOrderResponse>> findOrder(@Body FindOrderRequest request);
 }

+ 91 - 0
app/src/main/java/com/datarecovery/master/data/api/bean/MemberGoodsBean.java

@@ -0,0 +1,91 @@
+package com.datarecovery.master.data.api.bean;
+
+import androidx.databinding.BaseObservable;
+import androidx.databinding.Bindable;
+
+import com.datarecovery.master.BR;
+import com.datarecovery.master.module.member.MemberType;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.Objects;
+
+public class MemberGoodsBean extends BaseObservable {
+    @SerializedName("id")
+    private int id;
+    @SerializedName("name")
+    private String name;
+    @SerializedName("auths")
+    private String auths;
+    @SerializedName("amount")
+    private int amount;
+    @SerializedName("originalAmount")
+    private int originalAmount;
+    @SerializedName("sort")
+    private int sort;
+    @SerializedName("description")
+    private String description;
+
+    @SerializedName("popular")
+    private boolean popular;
+
+    private boolean isSelect;
+
+    private String[] scenesArray;
+
+    @Bindable
+    public boolean isSelect() {
+        return isSelect;
+    }
+
+    public void setSelect(boolean select) {
+        isSelect = select;
+        notifyPropertyChanged(BR.select);
+    }
+
+    public void setScenesArray(String[] scenesArray) {
+        this.scenesArray = scenesArray;
+    }
+
+
+    public String[] getScenesArray() {
+        return scenesArray;
+    }
+
+    public boolean isPopular() {
+        return popular;
+    }
+
+    public int getSort() {
+        return sort;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getAuths() {
+        return auths;
+    }
+
+    public float getAmount() {
+        return amount / 100f;
+    }
+
+    public float getOriginalAmount() {
+        return originalAmount / 100f;
+    }
+
+
+    public String getDescription() {
+        return description;
+    }
+
+    public boolean isSuperRecover() {
+        return Objects.equals(auths, MemberType.APP_SUPER_RECOVER);
+    }
+
+}

+ 62 - 0
app/src/main/java/com/datarecovery/master/data/api/bean/PayOptionsBean.java

@@ -0,0 +1,62 @@
+package com.datarecovery.master.data.api.bean;
+
+import androidx.annotation.DrawableRes;
+
+import com.datarecovery.master.R;
+import com.google.gson.annotations.SerializedName;
+
+public class PayOptionsBean {
+    @SerializedName("id")
+    private int id;
+    @SerializedName("payMethod")
+    private int payMethod;
+    @SerializedName("payPlatform")
+    private int payPlatform;
+    @SerializedName("title")
+    private String title;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public int getPayMethod() {
+        return payMethod;
+    }
+
+    public void setPayMethod(int payMethod) {
+        this.payMethod = payMethod;
+    }
+
+    public int getPayPlatform() {
+        return payPlatform;
+    }
+
+    public void setPayPlatform(int payPlatform) {
+        this.payPlatform = payPlatform;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getPayWayIcon() {
+        if (payPlatform == 1 && payMethod == 2) {
+            return R.drawable.icon_wechat_payment;
+        } else if (payPlatform == 4 && payMethod == 2) {
+            return R.drawable.icon_wechat_scan_payment;
+        } else if (payPlatform == 1 && payMethod == 1) {
+            return R.drawable.icon_alipay_payment;
+        } else if (payPlatform == 4 && payMethod == 1) {
+            return R.drawable.icon_alipay_scan_payment;
+        }
+        return 0;
+    }
+}

+ 54 - 0
app/src/main/java/com/datarecovery/master/data/api/bean/WechatPaymentSignBean.java

@@ -0,0 +1,54 @@
+package com.datarecovery.master.data.api.bean;
+
+import com.google.gson.annotations.SerializedName;
+
+public class WechatPaymentSignBean {
+    @SerializedName("appid")
+    private String appId;
+
+    @SerializedName("partnerid")
+    private String partnerId;
+
+    @SerializedName("prepayid")
+    private String prePayId;
+
+    @SerializedName("package")
+    private String packageName;
+
+    @SerializedName("noncestr")
+    private String randomStr;
+
+    @SerializedName("timestamp")
+    private String timeStamp;
+
+    @SerializedName("sign")
+    private String sign;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public String getPartnerId() {
+        return partnerId;
+    }
+
+    public String getPrePayId() {
+        return prePayId;
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public String getRandomStr() {
+        return randomStr;
+    }
+
+    public String getTimeStamp() {
+        return timeStamp;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+}

+ 13 - 0
app/src/main/java/com/datarecovery/master/data/api/request/FindOrderRequest.java

@@ -0,0 +1,13 @@
+package com.datarecovery.master.data.api.request;
+
+import com.google.gson.annotations.SerializedName;
+
+public class FindOrderRequest extends BaseRequest {
+
+    @SerializedName("auths")
+    private String[] auths;
+
+    public FindOrderRequest(String[] auths) {
+        this.auths = auths;
+    }
+}

+ 14 - 0
app/src/main/java/com/datarecovery/master/data/api/request/MemberDetailRequest.java

@@ -0,0 +1,14 @@
+package com.datarecovery.master.data.api.request;
+
+import com.google.gson.annotations.SerializedName;
+
+public class MemberDetailRequest extends BaseRequest {
+
+
+    @SerializedName("auths")
+    private String auths;
+
+    public MemberDetailRequest(String auths) {
+        this.auths = auths;
+    }
+}

+ 21 - 0
app/src/main/java/com/datarecovery/master/data/api/request/MemberPayRequest.java

@@ -0,0 +1,21 @@
+package com.datarecovery.master.data.api.request;
+
+import com.google.gson.annotations.SerializedName;
+
+public class MemberPayRequest extends BaseRequest {
+
+    @SerializedName("itemId")
+    private int itemId;
+
+    @SerializedName("payPlatform")
+    private int payPlatform;
+
+    @SerializedName("payMethod")
+    private int payMethod;
+
+    public MemberPayRequest(int itemId, int payPlatform, int payMethod) {
+        this.itemId = itemId;
+        this.payPlatform = payPlatform;
+        this.payMethod = payMethod;
+    }
+}

+ 12 - 0
app/src/main/java/com/datarecovery/master/data/api/request/PaymentStatusRequest.java

@@ -0,0 +1,12 @@
+package com.datarecovery.master.data.api.request;
+
+import com.google.gson.annotations.SerializedName;
+
+public class PaymentStatusRequest extends BaseRequest {
+    @SerializedName("outTradeNo")
+    private final String orderId;
+
+    public PaymentStatusRequest(String orderId) {
+        this.orderId = orderId;
+    }
+}

+ 40 - 0
app/src/main/java/com/datarecovery/master/data/api/response/FindOrderResponse.java

@@ -0,0 +1,40 @@
+package com.datarecovery.master.data.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+public class FindOrderResponse {
+
+
+    @SerializedName("id")
+    private int id;
+    @SerializedName("itemName")
+    private String itemName;
+    @SerializedName("outTradeNo")
+    private String outTradeNo;
+    @SerializedName("authCode")
+    private String authCode;
+    @SerializedName("tutorialUrl")
+    private String tutorialUrl;
+
+    public int getId() {
+        return id;
+    }
+
+    public String getItemName() {
+        return itemName;
+    }
+
+
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public String getAuthCode() {
+        return authCode;
+    }
+
+    public String getTutorialUrl() {
+        return tutorialUrl;
+    }
+
+}

+ 31 - 0
app/src/main/java/com/datarecovery/master/data/api/response/MemberDetailResponse.java

@@ -0,0 +1,31 @@
+package com.datarecovery.master.data.api.response;
+
+import com.datarecovery.master.data.api.bean.MemberGoodsBean;
+import com.datarecovery.master.data.api.bean.PayOptionsBean;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+public class MemberDetailResponse {
+
+
+    @SerializedName("list")
+    private List<MemberGoodsBean> list;
+    @SerializedName("payOptions")
+    private List<PayOptionsBean> payOptions;
+
+    @SerializedName("description")
+    private String description;
+
+    public String getDescription() {
+        return description;
+    }
+
+    public List<MemberGoodsBean> getList() {
+        return list;
+    }
+
+    public List<PayOptionsBean> getPayOptions() {
+        return payOptions;
+    }
+}

+ 56 - 0
app/src/main/java/com/datarecovery/master/data/api/response/MemberPayResponse.java

@@ -0,0 +1,56 @@
+package com.datarecovery.master.data.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+public class MemberPayResponse {
+
+
+    @SerializedName("outTradeNo")
+    private String outTradeNo;
+    @SerializedName("wechatPayQrcodeUrl")
+    private String wechatPayQrcodeUrl;
+    @SerializedName("wechatPayRedirectUrl")
+    private String wechatPayRedirectUrl;
+    @SerializedName("wechatPayPrepayJson")
+    private String wechatPayPrepayJson;
+    @SerializedName("alipayQrcodeHtml")
+    private String alipayQrcodeHtml;
+    @SerializedName("aliPaySubmitHtml")
+    private String aliPaySubmitHtml;
+    @SerializedName("alipayOrderString")
+    private String alipayOrderString;
+    @SerializedName("appAccountToken")
+    private String appAccountToken;
+
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public String getWechatPayQrcodeUrl() {
+        return wechatPayQrcodeUrl;
+    }
+
+    public String getWechatPayRedirectUrl() {
+        return wechatPayRedirectUrl;
+    }
+
+    public String getWechatPayPrepayJson() {
+        return wechatPayPrepayJson;
+    }
+
+    public String getAlipayQrcodeHtml() {
+        return alipayQrcodeHtml;
+    }
+
+    public String getAliPaySubmitHtml() {
+        return aliPaySubmitHtml;
+    }
+
+    public String getAlipayOrderString() {
+        return alipayOrderString;
+    }
+
+    public String getAppAccountToken() {
+        return appAccountToken;
+    }
+}

+ 13 - 0
app/src/main/java/com/datarecovery/master/data/api/response/PaymentStatusResponse.java

@@ -0,0 +1,13 @@
+package com.datarecovery.master.data.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+public class PaymentStatusResponse {
+    @SerializedName("payStatus")
+    private int status;
+
+    public int getStatus() {
+        return status;
+    }
+
+}

+ 3 - 3
app/src/main/java/com/datarecovery/master/data/consts/Constants.java

@@ -5,7 +5,7 @@ import com.datarecovery.master.BuildConfig;
 public class Constants {
 
 
-    private static final String Atmob_Server_Base_URL_LOCAL = "http://192.168.10.68:56389";
+    private static final String Atmob_Server_Base_URL_LOCAL = "http://192.168.10.68:8880";
     public static final String Atmob_Server_Base_URL_REMOTE = BuildConfig.HOST;
     public static final String Atmob_Server_Base_URL = BuildConfig.isLocalNetwork ? Atmob_Server_Base_URL_LOCAL : Atmob_Server_Base_URL_REMOTE;
 
@@ -14,9 +14,9 @@ public class Constants {
     public static final int App_DefaultAppId = 0;
     public static final int App_DefaultTgPlatformId = 0;
 
-    public static final String PRIVACY_POLICY = "https://cdn.v8dashen.com/manyue/static/zrdwzs-my-privacy.html";
+    public static final String PRIVACY_POLICY = "http://cdn.myaskai.cn/manyue/static/wjsjhfds-manyue-a-privacy.html";
 
-    public static final String USER_AGREEMENT = "https://cdn.v8dashen.com/manyue/static/zrdwzs-my-clause.html";
+    public static final String USER_AGREEMENT = "http://cdn.myaskai.cn/manyue/static/wjsjhfds-manyue-clause.html";
 
 
 }

+ 1 - 1
app/src/main/java/com/datarecovery/master/data/consts/ErrorCode.java

@@ -1,5 +1,5 @@
 package com.datarecovery.master.data.consts;
 
 public interface ErrorCode {
-    int ERROR_CODE_VERIFICATION_CODE_ERROR = 1005;
+    int ERROR_CODE_VERIFICATION_CODE_ERROR = 2002;
 }

+ 75 - 0
app/src/main/java/com/datarecovery/master/data/repositories/MemberRepository.java

@@ -0,0 +1,75 @@
+package com.datarecovery.master.data.repositories;
+
+
+import com.atmob.app.lib.handler.RxHttpHandler;
+import com.datarecovery.master.data.api.AtmobApi;
+import com.datarecovery.master.data.api.request.MemberDetailRequest;
+import com.datarecovery.master.data.api.request.MemberPayRequest;
+import com.datarecovery.master.data.api.request.OrderPageRequest;
+import com.datarecovery.master.data.api.request.PaymentStatusRequest;
+import com.datarecovery.master.data.api.response.MemberDetailResponse;
+import com.datarecovery.master.data.api.response.MemberPayResponse;
+import com.datarecovery.master.data.api.response.OrderPageResponse;
+import com.datarecovery.master.data.api.response.PaymentStatusResponse;
+import com.datarecovery.master.module.member.MemberType;
+import com.datarecovery.master.utils.BoxingUtil;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import atmob.reactivex.rxjava3.core.Single;
+import atmob.rxjava.utils.RxJavaUtil;
+
+@Singleton
+public class MemberRepository {
+
+
+    private final AtmobApi atmobApi;
+    private final DeviceFuncRepository deviceFuncRepository;
+
+    @Inject
+    public MemberRepository(AtmobApi atmobApi, DeviceFuncRepository deviceFuncRepository) {
+        this.atmobApi = atmobApi;
+        this.deviceFuncRepository = deviceFuncRepository;
+    }
+
+
+    public Single<MemberDetailResponse> memberDetail(@MemberType String type) {
+        return atmobApi.memberDetail(new MemberDetailRequest(type))
+                .compose(RxHttpHandler.handle(false))
+                .compose(RxJavaUtil.SingleSchedule.io2Main());
+    }
+
+    public Single<MemberPayResponse> requestPayOrder(int itemId, int payPlatform, int payMethod) {
+        return atmobApi.requestPayOrder(new MemberPayRequest(itemId, payPlatform, payMethod))
+                .compose(RxHttpHandler.handle(false))
+                .compose(RxJavaUtil.SingleSchedule.io2Main());
+    }
+
+
+    /**
+     * 0-查询失败,继续轮询
+     * 1-未支付,继续轮询
+     * 2-支付成功
+     * 3-支付关闭
+     * 4-已退款
+     */
+    public Single<Boolean> getPayStatus(String orderId) {
+        return atmobApi.getPayStatus(new PaymentStatusRequest(orderId))
+                .compose(RxHttpHandler.handle(false))
+                .map(PaymentStatusResponse::getStatus)
+                .map(integer -> {
+                    if (BoxingUtil.boxing(integer) == 0 || BoxingUtil.boxing(integer) == 1) {
+                        throw new Exception("支付未完成, status ==> " + integer);
+                    }
+                    return integer;
+                })
+                .retryWhen(RxJavaUtil.retryWhen(null, 100, 3, TimeUnit.SECONDS))
+                .onErrorReturnItem(0)
+                .map(integer -> integer == 2)
+                .compose(RxJavaUtil.SingleSchedule.io2Main())
+                .doOnTerminate(deviceFuncRepository::refreshFuncAuths);
+    }
+}

+ 10 - 0
app/src/main/java/com/datarecovery/master/data/repositories/PayRepository.java

@@ -3,7 +3,9 @@ package com.datarecovery.master.data.repositories;
 
 import com.atmob.app.lib.handler.RxHttpHandler;
 import com.datarecovery.master.data.api.AtmobApi;
+import com.datarecovery.master.data.api.request.FindOrderRequest;
 import com.datarecovery.master.data.api.request.OrderPageRequest;
+import com.datarecovery.master.data.api.response.FindOrderResponse;
 import com.datarecovery.master.data.api.response.OrderPageResponse;
 
 import javax.inject.Inject;
@@ -32,4 +34,12 @@ public class PayRepository {
                 .compose(RxHttpHandler.handle(true))
                 .compose(RxJavaUtil.SingleSchedule.io2Main());
     }
+
+    public Single<FindOrderResponse> findOrder(String[] auths) {
+        return atmobApi.findOrder(new FindOrderRequest(auths))
+                .compose(RxHttpHandler.handle(true))
+                .compose(RxJavaUtil.SingleSchedule.io2Main());
+    }
+
+
 }

+ 68 - 0
app/src/main/java/com/datarecovery/master/dialog/AlipayQrCodeDialog.java

@@ -0,0 +1,68 @@
+package com.datarecovery.master.dialog;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.NonNull;
+
+import com.atmob.app.lib.base.BaseDialog;
+import com.atmob.common.ui.SizeUtil;
+import com.datarecovery.master.R;
+import com.datarecovery.master.databinding.DialogAlipayQrCodeBinding;
+import com.datarecovery.master.module.member.MemberViewModel;
+
+import atmob.reactivex.rxjava3.disposables.Disposable;
+
+@BaseDialog.FullScreen
+public class AlipayQrCodeDialog extends BaseDialog<DialogAlipayQrCodeBinding> {
+    private static final String HTML_TEMPLATE = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/><title>Alipay QR Code</title></head><body>${qr_code_html}</body></html>";
+    private @atmob.reactivex.rxjava3.annotations.NonNull Disposable queryOrderDisposable;
+    private String orderId;
+    private MemberViewModel memberViewModel;
+
+    @SuppressLint("SetJavaScriptEnabled")
+    public AlipayQrCodeDialog(@NonNull Context context) {
+        super(context, R.style.Theme_Common_Dialog);
+        setCanceledOnTouchOutside(false);
+        binding.alipayQrCodeWebView.getSettings().setJavaScriptEnabled(true);
+        binding.alipayQrCodeWebView.getSettings().setLoadsImagesAutomatically(true);
+        binding.alipayQrCodeWebView.setInitialScale((int) (SizeUtil.getScreenWidth() * 63.88888888888889f / 110));
+        binding.alipayQrCodeWebView.setWebViewClient(new WebViewClient() {
+            @Override
+            public boolean shouldOverrideUrlLoading(WebView view, String url) {
+                return false;
+            }
+
+            @Override
+            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+                return false;
+            }
+        });
+        binding.setOnCloseClickListener(v -> dismiss());
+    }
+
+    @Override
+    protected void onDismiss() {
+        super.onDismiss();
+        if (queryOrderDisposable != null && !queryOrderDisposable.isDisposed()) {
+            queryOrderDisposable.dispose();
+            memberViewModel.queryOrderStatus(orderId, true);
+        }
+        binding.alipayQrCodeWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
+    }
+
+    public void show(String qrCodeHtml, String orderId, MemberViewModel memberViewModel) {
+        this.memberViewModel = memberViewModel;
+        this.orderId = orderId;
+        this.queryOrderDisposable = memberViewModel.queryOrderStatus(orderId, false);
+        binding.alipayQrCodeWebView.loadDataWithBaseURL(null, HTML_TEMPLATE.replace("${qr_code_html}", qrCodeHtml), "text/html", "utf-8", null);
+        super.show();
+    }
+
+    public String getCurrentOrderId() {
+        return orderId;
+    }
+}

+ 93 - 0
app/src/main/java/com/datarecovery/master/dialog/ChoosePaymentWayDialog.java

@@ -0,0 +1,93 @@
+package com.datarecovery.master.dialog;
+
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.MutableLiveData;
+
+
+import com.atmob.app.lib.base.BaseDialog;
+import com.datarecovery.master.R;
+import com.datarecovery.master.data.api.bean.PayOptionsBean;
+import com.datarecovery.master.databinding.DialogChoosePaymentWayBinding;
+import com.datarecovery.master.databinding.LayoutItemPaymentWayBinding;
+import com.datarecovery.master.utils.ToastUtil;
+
+import java.util.List;
+
+@BaseDialog.FullScreen(height = false, gravity = Gravity.BOTTOM)
+public class ChoosePaymentWayDialog extends BaseDialog<DialogChoosePaymentWayBinding> {
+
+    private ActionHandler actionHandler;
+
+    private final List<PayOptionsBean> paymentWayList;
+
+    private final MutableLiveData<Integer> selectedPosition = new MutableLiveData<>(0);
+
+    @SuppressLint("UseCompatLoadingForDrawables")
+    public ChoosePaymentWayDialog(@NonNull Context context, LifecycleOwner lifecycleOwner, List<PayOptionsBean> paymentWayList) {
+        super(context, R.style.Theme_Common_BottomSheetDialog);
+        this.paymentWayList = paymentWayList;
+        setCancelable(false);
+        binding.setOnCloseClickListener(v -> dismiss());
+        binding.setOnPayClickListener(v -> {
+            Integer index = selectedPosition.getValue();
+            if (actionHandler != null && index != null) {
+                PayOptionsBean payOptionsBean = paymentWayList.get(index);
+                actionHandler.onPayClick(payOptionsBean.getPayPlatform(), payOptionsBean.getPayMethod());
+            }
+            dismiss();
+        });
+        if (paymentWayList == null) {
+            return;
+        }
+        LayoutInflater layoutInflater = LayoutInflater.from(context);
+        binding.llPay.removeAllViews();
+        for (int i = 0; i < paymentWayList.size(); i++) {
+            PayOptionsBean paymentWayBean = paymentWayList.get(i);
+            LayoutItemPaymentWayBinding itemPaymentWayBinding = LayoutItemPaymentWayBinding.inflate(layoutInflater, binding.llPay, true);
+            if (paymentWayBean.getPayWayIcon() != 0) {
+                itemPaymentWayBinding.setPaymentWayIcon(context.getResources().getDrawable(paymentWayBean.getPayWayIcon()));
+            }
+            itemPaymentWayBinding.setSelectedPosition(selectedPosition);
+            itemPaymentWayBinding.setPosition(i);
+            itemPaymentWayBinding.setPaymentWayName(paymentWayBean.getTitle());
+            itemPaymentWayBinding.setLifecycleOwner(lifecycleOwner);
+            int finalI = i;
+            itemPaymentWayBinding.getRoot().setOnClickListener(v -> selectedPosition.setValue(finalI));
+        }
+    }
+
+
+    public void paymentShow() {
+        if (paymentWayList == null || paymentWayList.size() == 0) {
+            ToastUtil.show(R.string.no_pay_way, ToastUtil.LENGTH_SHORT);
+            return;
+        }
+        if (paymentWayList.size() == 1) {
+
+        } else {
+            show();
+        }
+    }
+
+
+    @Override
+    protected void onDismiss() {
+        super.onDismiss();
+    }
+
+    public interface ActionHandler {
+        void onPayClick(int payPlatform, int payMethod);
+    }
+
+    public ChoosePaymentWayDialog setActionHandler(ActionHandler actionHandler) {
+        this.actionHandler = actionHandler;
+        return this;
+    }
+}

+ 43 - 0
app/src/main/java/com/datarecovery/master/dialog/MemberRetentionDialog.java

@@ -0,0 +1,43 @@
+package com.datarecovery.master.dialog;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.atmob.app.lib.base.BaseDialog;
+import com.datarecovery.master.R;
+import com.datarecovery.master.databinding.DialogMemberRetentionBinding;
+
+@BaseDialog.FullScreen
+public class MemberRetentionDialog extends BaseDialog<DialogMemberRetentionBinding> {
+
+    private ActionHandler actionHandler;
+
+    public MemberRetentionDialog(@NonNull Context context) {
+        super(context, R.style.Theme_Common_Dialog);
+        setCancelable(false);
+        binding.setOnCloseClickListener(v -> {
+            if (actionHandler != null) {
+                actionHandler.onCloseClick();
+            }
+            dismiss();
+        });
+        binding.setOnContinueClickListener(v -> {
+            if (actionHandler != null) {
+                actionHandler.onContinueClick();
+            }
+            dismiss();
+        });
+    }
+
+    public MemberRetentionDialog setActionHandler(ActionHandler actionHandler) {
+        this.actionHandler = actionHandler;
+        return this;
+    }
+
+    public interface ActionHandler {
+        void onCloseClick();
+
+        void onContinueClick();
+    }
+}

+ 60 - 0
app/src/main/java/com/datarecovery/master/dialog/WechatPayQrCodeDialog.java

@@ -0,0 +1,60 @@
+package com.datarecovery.master.dialog;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+
+import com.atmob.app.lib.base.BaseDialog;
+import com.datarecovery.master.R;
+import com.datarecovery.master.databinding.DialogWechatPayQrCodeBinding;
+import com.datarecovery.master.module.member.MemberViewModel;
+import com.datarecovery.master.utils.QrCodeUtil;
+
+import atmob.reactivex.rxjava3.disposables.Disposable;
+import atmob.rxjava.utils.RxJavaUtil;
+
+@BaseDialog.FullScreen
+public class WechatPayQrCodeDialog extends BaseDialog<DialogWechatPayQrCodeBinding> {
+
+    private Disposable generateQRDisposable;
+    private @atmob.reactivex.rxjava3.annotations.NonNull Disposable queryOrderDisposable;
+    private String orderId;
+    private MemberViewModel memberViewModel;
+
+    public WechatPayQrCodeDialog(@NonNull Context context) {
+        super(context, R.style.Theme_Common_Dialog);
+        binding.setOnCloseClickListener(v -> dismiss());
+    }
+
+    @Override
+    protected void onDismiss() {
+        super.onDismiss();
+        binding.wechatPayQrCode.setImageBitmap(null);
+        if (queryOrderDisposable != null && !queryOrderDisposable.isDisposed()) {
+            queryOrderDisposable.dispose();
+            memberViewModel.queryOrderStatus(orderId, true);
+        }
+        if (generateQRDisposable != null && !generateQRDisposable.isDisposed()) {
+            generateQRDisposable.dispose();
+        }
+    }
+
+    public void show(String qrCodeData, String orderId, MemberViewModel memberViewModel) {
+        this.memberViewModel = memberViewModel;
+        this.orderId = orderId;
+        this.queryOrderDisposable = memberViewModel.queryOrderStatus(orderId, false);
+        if (generateQRDisposable != null && !generateQRDisposable.isDisposed()) {
+            generateQRDisposable.dispose();
+        }
+        generateQRDisposable = RxJavaUtil.doInBackground(() -> QrCodeUtil.generateQrCode(qrCodeData, 300, R.drawable.icon_wechat_payment),
+                bitmap -> binding.wechatPayQrCode.setImageBitmap(bitmap), throwable -> {
+                    // TODO: 24/8/2023 show error
+                });
+        super.show();
+    }
+
+    public String getCurrentOrderId() {
+        return orderId;
+    }
+}

+ 3 - 1
app/src/main/java/com/datarecovery/master/module/homepage/HomePageViewModel.java

@@ -8,6 +8,8 @@ import com.datarecovery.master.R;
 import com.datarecovery.master.module.audiorecover.AudioRecoverActivity;
 import com.datarecovery.master.module.filerecover.FileRecoverActivity;
 import com.datarecovery.master.module.imgrecover.ImageRecoverActivity;
+import com.datarecovery.master.module.member.MemberActivity;
+import com.datarecovery.master.module.member.MemberType;
 import com.datarecovery.master.module.videorecover.VideoRecoverActivity;
 import com.datarecovery.master.utils.PermissionUtil;
 import com.datarecovery.master.utils.xfile.XFilePermission;
@@ -77,7 +79,7 @@ public class HomePageViewModel extends BaseViewModel {
     }
 
     public void onWxMessageRecoveryClick() {
-
+        MemberActivity.start(ActivityUtil.getTopActivity(), MemberType.APP_WX_MESSAGE_RECOVER);
     }
 
     public void onWxFriendRecoveryClick() {

+ 121 - 0
app/src/main/java/com/datarecovery/master/module/member/GoodsItemAdapter.java

@@ -0,0 +1,121 @@
+package com.datarecovery.master.module.member;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.recyclerview.widget.AsyncListDiffer;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.datarecovery.master.data.api.bean.MemberGoodsBean;
+import com.datarecovery.master.databinding.ItemMemberGoodsBinding;
+
+import java.util.List;
+import java.util.Objects;
+
+public class GoodsItemAdapter extends RecyclerView.Adapter<GoodsItemAdapter.ViewHolder> {
+
+    private final AsyncListDiffer<MemberGoodsBean> listDiffer;
+
+
+    private final LifecycleOwner lifecycleOwner;
+
+    private onItemSelectListener onItemSelectListener;
+
+    private MemberGoodsBean selectBean;
+
+    public void setOnItemSelectListener(GoodsItemAdapter.onItemSelectListener onItemSelectListener) {
+        this.onItemSelectListener = onItemSelectListener;
+    }
+
+    public GoodsItemAdapter(LifecycleOwner lifecycleOwner) {
+        this.lifecycleOwner = lifecycleOwner;
+        listDiffer = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<MemberGoodsBean>() {
+            @Override
+            public boolean areItemsTheSame(@NonNull MemberGoodsBean oldItem, @NonNull MemberGoodsBean newItem) {
+                return oldItem.getId() == newItem.getId();
+            }
+
+            @Override
+            public boolean areContentsTheSame(@NonNull MemberGoodsBean oldItem, @NonNull MemberGoodsBean newItem) {
+                return Objects.equals(oldItem.getName(), newItem.getName())
+                        && Objects.equals(oldItem.getOriginalAmount(), newItem.getOriginalAmount())
+                        && Objects.equals(oldItem.getAmount(), newItem.getAmount())
+                        && Objects.equals(oldItem.getDescription(), newItem.getDescription());
+            }
+        });
+    }
+
+    public void submit(List<MemberGoodsBean> list) {
+        listDiffer.submitList(list, () -> {
+            if (list == null) {
+                return;
+            }
+            for (MemberGoodsBean memberGoodsBean : list) {
+                if (Objects.equals(memberGoodsBean.getAuths(), MemberType.APP_SUPER_RECOVER)) {
+                    memberGoodsBean.setSelect(true);
+                    setSelectBean(memberGoodsBean);
+                    break;
+                }
+            }
+        });
+    }
+
+    public void setSelectBean(MemberGoodsBean memberGoodsBean) {
+        this.selectBean = memberGoodsBean;
+        if (onItemSelectListener != null) {
+            onItemSelectListener.onItemSelect(memberGoodsBean);
+        }
+    }
+
+    @NonNull
+    @Override
+    public GoodsItemAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        Context context = parent.getContext();
+        LayoutInflater layoutInflater = LayoutInflater.from(context);
+        return new ViewHolder(ItemMemberGoodsBinding.inflate(layoutInflater, parent, false));
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull GoodsItemAdapter.ViewHolder holder, int position) {
+        holder.bind(listDiffer.getCurrentList().get(position));
+    }
+
+    @Override
+    public int getItemCount() {
+        return listDiffer.getCurrentList().size();
+    }
+
+    public class ViewHolder extends RecyclerView.ViewHolder {
+
+        private final ItemMemberGoodsBinding binding;
+
+        public ViewHolder(@NonNull ItemMemberGoodsBinding binding) {
+            super(binding.getRoot());
+            this.binding = binding;
+            binding.setLifecycleOwner(lifecycleOwner);
+            binding.getRoot().setOnClickListener(v -> {
+                MemberGoodsBean clickBean = binding.getGoodsBean();
+                if (selectBean != null && selectBean.getId() != clickBean.getId()) {
+                    selectBean.setSelect(false);
+                    clickBean.setSelect(true);
+                    setSelectBean(clickBean);
+                }
+            });
+        }
+
+        public void bind(MemberGoodsBean goodsBean) {
+            binding.setGoodsBean(goodsBean);
+        }
+    }
+
+    public interface onItemSelectListener {
+        void onItemSelect(MemberGoodsBean goodsBean);
+    }
+
+
+}

+ 227 - 0
app/src/main/java/com/datarecovery/master/module/member/MemberActivity.java

@@ -0,0 +1,227 @@
+package com.datarecovery.master.module.member;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+
+import com.atmob.app.lib.base.BaseActivity;
+import com.datarecovery.master.R;
+import com.datarecovery.master.databinding.ActivityMemberBinding;
+import com.datarecovery.master.dialog.AlipayQrCodeDialog;
+import com.datarecovery.master.dialog.ChoosePaymentWayDialog;
+import com.datarecovery.master.dialog.CommonLoadingDialog;
+import com.datarecovery.master.dialog.MemberRetentionDialog;
+import com.datarecovery.master.dialog.WechatPayQrCodeDialog;
+import com.datarecovery.master.module.wxrecover.WeChatRecoverActivity;
+import com.datarecovery.master.utils.BoxingUtil;
+import com.datarecovery.master.utils.GridLayoutItemDecoration;
+import com.datarecovery.master.utils.ToastUtil;
+import com.gyf.immersionbar.ImmersionBar;
+
+import java.util.Objects;
+
+import dagger.hilt.android.AndroidEntryPoint;
+
+@AndroidEntryPoint
+public class MemberActivity extends BaseActivity<ActivityMemberBinding> {
+
+
+    private static final String MEMBER_TYPE = "member_type";
+    private MemberViewModel memberViewModel;
+
+    private GoodsItemAdapter goodsItemAdapter;
+
+    private NormalScenesAdapter normalScenesAdapter;
+    private SuperScenesAdapter superScenesAdapter;
+    private GridLayoutManager gridLayoutManager;
+    private GridLayoutItemDecoration gridLayoutItemDecoration;
+    private MemberEvaluateAdapter memberEvaluateAdapter;
+    private MemberRetentionDialog memberRetentionDialog;
+    private ChoosePaymentWayDialog choosePaymentWayDialog;
+    private CommonLoadingDialog commonLoadingDialog;
+    private AlipayQrCodeDialog alipayQrCodeDialog;
+    private WechatPayQrCodeDialog wechatPayQrCodeDialog;
+
+
+    public static void start(Context context, @MemberType String type) {
+        Intent intent = new Intent(context, MemberActivity.class);
+        if (!(context instanceof Activity)) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        intent.putExtra(MEMBER_TYPE, type);
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        initView();
+        initObserver();
+        initData();
+    }
+
+    private void initData() {
+        Intent intent = getIntent();
+        if (intent != null) {
+            memberViewModel.setMemberType(intent.getStringExtra(MEMBER_TYPE));
+        }
+    }
+
+    private void initView() {
+        addTopStatusBarHeight(binding.toolbar);
+        goodsItemAdapter = new GoodsItemAdapter(this);
+        binding.memberDetailList.setAdapter(goodsItemAdapter);
+        binding.memberDetailList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
+        goodsItemAdapter.setOnItemSelectListener(goodsBean -> memberViewModel.setSelectBean(goodsBean));
+        normalScenesAdapter = new NormalScenesAdapter();
+        superScenesAdapter = new SuperScenesAdapter();
+        gridLayoutManager = new GridLayoutManager(this, 4);
+        binding.scenesRyView.setLayoutManager(gridLayoutManager);
+        gridLayoutItemDecoration = new GridLayoutItemDecoration();
+        binding.scenesRyView.addItemDecoration(gridLayoutItemDecoration);
+
+        memberEvaluateAdapter = new MemberEvaluateAdapter();
+        binding.userEvaluateRyView.setLayoutManager(new LinearLayoutManager(this));
+        binding.userEvaluateRyView.setAdapter(memberEvaluateAdapter);
+
+        binding.iconBack.setOnClickListener(v -> onBackPressed());
+    }
+
+    private void initObserver() {
+        memberViewModel.getOnSubscribeSuccessEvent().observe(this, orderId -> {
+            dismissQrCodeDialog(orderId);
+            WeChatRecoverActivity.start(this);
+            finish();
+        });
+        memberViewModel.getShowAliQRPaymentEvent().observe(this, this::showAlipayQrCodeDialog);
+        memberViewModel.getShowWxQRPaymentEvent().observe(this, this::showWxQrCodeDialog);
+        memberViewModel.getShowLoadingEvent().observe(this, this::showLoading);
+        memberViewModel.getMemberGoodsList().observe(this, goodsItemAdapter::submit);
+        memberViewModel.getSelectBean().observe(this, bean -> {
+            if (bean == null) {
+                return;
+            }
+            if (Objects.equals(bean.getAuths(), MemberType.APP_SUPER_RECOVER)) {
+                gridLayoutManager.setSpanCount(4);
+                gridLayoutItemDecoration.setParam(4, 0, 0.0361111111111111f);
+                superScenesAdapter.setData(memberViewModel.getSuperScenesBeans());
+                binding.scenesRyView.setAdapter(superScenesAdapter);
+            } else {
+                gridLayoutManager.setSpanCount(2);
+                gridLayoutItemDecoration.setParam(2, 0, 0.0166666666666667f);
+                normalScenesAdapter.setData(bean.getScenesArray());
+                binding.scenesRyView.setAdapter(normalScenesAdapter);
+            }
+        });
+        memberViewModel.getEvaluateList().observe(this, evaluateBeans -> memberEvaluateAdapter.submit(evaluateBeans));
+        memberViewModel.getShowChoicePayWayDialog().observe(this, o -> showChoosePaymentWayDialog());
+    }
+
+    private void showWxQrCodeDialog(Pair<String, String> params) {
+        if (params == null || params.first == null || params.second == null) {
+            return;
+        }
+        if (wechatPayQrCodeDialog == null) {
+            wechatPayQrCodeDialog = new WechatPayQrCodeDialog(this);
+        }
+        wechatPayQrCodeDialog.show(params.first, params.second, memberViewModel);
+    }
+
+    private void showAlipayQrCodeDialog(Pair<String, String> params) {
+        if (params == null || params.first == null || params.second == null) {
+            return;
+        }
+        if (alipayQrCodeDialog == null) {
+            alipayQrCodeDialog = new AlipayQrCodeDialog(this);
+        }
+        alipayQrCodeDialog.show(params.first, params.second, memberViewModel);
+    }
+
+    private void dismissQrCodeDialog(String orderId) {
+        if (alipayQrCodeDialog != null) {
+            if (Objects.equals(orderId, alipayQrCodeDialog.getCurrentOrderId())) {
+                alipayQrCodeDialog.dismiss();
+            }
+        }
+        if (wechatPayQrCodeDialog != null) {
+            if (Objects.equals(orderId, wechatPayQrCodeDialog.getCurrentOrderId())) {
+                wechatPayQrCodeDialog.dismiss();
+            }
+        }
+    }
+
+
+    private void showLoading(Boolean show) {
+        if (BoxingUtil.boxing(show)) {
+            if (commonLoadingDialog == null) {
+                commonLoadingDialog = new CommonLoadingDialog(this);
+                commonLoadingDialog.setMessageGone();
+            }
+            commonLoadingDialog.show();
+        } else {
+            if (commonLoadingDialog != null) {
+                commonLoadingDialog.dismiss();
+            }
+        }
+    }
+
+    private void showChoosePaymentWayDialog() {
+        if (choosePaymentWayDialog == null) {
+            choosePaymentWayDialog = new ChoosePaymentWayDialog(this, this, memberViewModel.getPayWayList().getValue());
+        }
+        choosePaymentWayDialog.setActionHandler((payPlatform, payMethod) -> memberViewModel.submitOrder(payPlatform, payMethod));
+        choosePaymentWayDialog.paymentShow();
+    }
+
+    private void showMemberRetentionDialog() {
+        if (memberRetentionDialog == null) {
+            memberRetentionDialog = new MemberRetentionDialog(this)
+                    .setActionHandler(new MemberRetentionDialog.ActionHandler() {
+                        @Override
+                        public void onCloseClick() {
+                            finish();
+                        }
+
+                        @Override
+                        public void onContinueClick() {
+                            memberViewModel.onRetainMemberSubscribeClick();
+                        }
+                    });
+        }
+        memberRetentionDialog.show();
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (!memberViewModel.isMember()) {
+            showMemberRetentionDialog();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+    @Override
+    protected void configImmersion(@NonNull ImmersionBar immersionBar) {
+        immersionBar.statusBarDarkFont(true);
+    }
+
+
+    @Override
+    protected void initViewModel() {
+        super.initViewModel();
+        memberViewModel = getViewModelProvider().get(MemberViewModel.class);
+        binding.setMemberViewModel(memberViewModel);
+    }
+
+    @Override
+    protected boolean shouldImmersion() {
+        return true;
+    }
+}

+ 72 - 0
app/src/main/java/com/datarecovery/master/module/member/MemberEvaluateAdapter.java

@@ -0,0 +1,72 @@
+package com.datarecovery.master.module.member;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.AsyncListDiffer;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.datarecovery.master.databinding.ItemMemberEvaluateBinding;
+import com.datarecovery.master.module.member.bean.EvaluateBean;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MemberEvaluateAdapter extends RecyclerView.Adapter<MemberEvaluateAdapter.ViewHolder> {
+
+    private final AsyncListDiffer<EvaluateBean> listDiffer;
+
+    public MemberEvaluateAdapter() {
+        listDiffer = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<EvaluateBean>() {
+            @Override
+            public boolean areItemsTheSame(@NonNull EvaluateBean oldItem, @NonNull EvaluateBean newItem) {
+                return Objects.equals(oldItem.getName(), newItem.getName());
+            }
+
+            @Override
+            public boolean areContentsTheSame(@NonNull EvaluateBean oldItem, @NonNull EvaluateBean newItem) {
+                return Objects.equals(oldItem.getContent(), newItem.getContent());
+            }
+        });
+    }
+
+    @NonNull
+    @Override
+    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        Context context = parent.getContext();
+        LayoutInflater layoutInflater = LayoutInflater.from(context);
+        return new ViewHolder(ItemMemberEvaluateBinding.inflate(layoutInflater, parent, false));
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+        EvaluateBean evaluateBean = listDiffer.getCurrentList().get(position);
+        holder.bind(evaluateBean);
+    }
+
+    @Override
+    public int getItemCount() {
+        return listDiffer.getCurrentList().size();
+    }
+
+    public void submit(List<EvaluateBean> evaluateBeans) {
+        listDiffer.submitList(evaluateBeans);
+    }
+
+    protected static class ViewHolder extends RecyclerView.ViewHolder {
+
+        private final ItemMemberEvaluateBinding binding;
+
+        public ViewHolder(@NonNull ItemMemberEvaluateBinding binding) {
+            super(binding.getRoot());
+            this.binding = binding;
+        }
+
+        public void bind(EvaluateBean evaluateBean) {
+            binding.setEvaluateBean(evaluateBean);
+        }
+    }
+}

+ 30 - 0
app/src/main/java/com/datarecovery/master/module/member/MemberType.java

@@ -0,0 +1,30 @@
+package com.datarecovery.master.module.member;
+
+
+import androidx.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@StringDef({
+        MemberType.APP_WX_MESSAGE_RECOVER,
+        MemberType.APP_WX_FRIEND_RECOVER,
+        MemberType.APP_IMAGE_RECOVER,
+        MemberType.APP_FILE_RECOVER,
+        MemberType.APP_VIDEO_RECOVER,
+        MemberType.APP_AUDIO_RECOVER,
+        MemberType.APP_IMAGE_CLEAN,
+        MemberType.APP_SUPER_RECOVER
+})
+@Retention(RetentionPolicy.SOURCE)
+public @interface MemberType {
+    String APP_WX_MESSAGE_RECOVER = "app_wx_message_recover";
+    String APP_WX_FRIEND_RECOVER = "app_wx_friend_recover";
+    String APP_IMAGE_RECOVER = "app_image_recover";
+    String APP_FILE_RECOVER = "app_file_recover";
+    String APP_VIDEO_RECOVER = "app_video_recover";
+    String APP_AUDIO_RECOVER = "app_audio_recover";
+    String APP_IMAGE_CLEAN = "app_image_clean";
+    String APP_SUPER_RECOVER = "app_super_recover";
+
+}

+ 381 - 0
app/src/main/java/com/datarecovery/master/module/member/MemberViewModel.java

@@ -0,0 +1,381 @@
+package com.datarecovery.master.module.member;
+
+import android.text.TextUtils;
+import android.util.Pair;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+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.runtime.ActivityUtil;
+import com.atmob.common.runtime.ContextUtil;
+import com.datarecovery.master.R;
+import com.datarecovery.master.data.api.bean.MemberGoodsBean;
+import com.datarecovery.master.data.api.bean.PayOptionsBean;
+import com.datarecovery.master.data.api.bean.WechatPaymentSignBean;
+import com.datarecovery.master.data.api.response.MemberDetailResponse;
+import com.datarecovery.master.data.api.response.MemberPayResponse;
+import com.datarecovery.master.data.repositories.AccountRepository;
+import com.datarecovery.master.data.repositories.MemberRepository;
+import com.datarecovery.master.module.login.LoginActivity;
+import com.datarecovery.master.module.member.bean.EvaluateBean;
+import com.datarecovery.master.module.member.bean.SuperScenesBean;
+import com.datarecovery.master.utils.BoxingUtil;
+import com.datarecovery.master.utils.ToastUtil;
+import com.google.gson.Gson;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+
+import atmob.reactivex.rxjava3.annotations.NonNull;
+import atmob.reactivex.rxjava3.core.SingleObserver;
+import atmob.reactivex.rxjava3.disposables.Disposable;
+import atmob.rxjava.utils.RxJavaUtil;
+import dagger.hilt.android.lifecycle.HiltViewModel;
+import plus.pay.AgilePay;
+import plus.pay.alipay.AlipayInfo;
+import plus.pay.listener.AgilePayState;
+import plus.pay.wxpay.WXpayInfo;
+
+
+@HiltViewModel
+public class MemberViewModel extends BaseViewModel {
+
+
+    private final MemberRepository memberRepository;
+
+    private final MutableLiveData<List<MemberGoodsBean>> memberGoodsList = new MutableLiveData<>();
+    private final MutableLiveData<List<PayOptionsBean>> payWayList = new MutableLiveData<>();
+    private final MutableLiveData<MemberGoodsBean> selectBean = new MutableLiveData<>();
+    private final MutableLiveData<String> serviceContentTxt = new MutableLiveData<>();
+    private final MutableLiveData<List<EvaluateBean>> evaluateList = new MutableLiveData<>();
+
+    private final SingleLiveEvent<String> onSubscribeSuccessEvent = new SingleLiveEvent<>();
+    private final Gson gson;
+    private final AccountRepository accountRepository;
+    private List<SuperScenesBean> superScenesBeans;
+
+    private final SingleLiveEvent<Boolean> showLoadingEvent = new SingleLiveEvent<>();
+    private final SingleLiveEvent<?> showChoicePayWayDialog = new SingleLiveEvent<>();
+
+    private final SingleLiveEvent<Pair<String, String>> showWxQRPaymentEvent = new SingleLiveEvent<>();
+    private final SingleLiveEvent<Pair<String, String>> showAliQRPaymentEvent = new SingleLiveEvent<>();
+    @MemberType
+    private String memberType;
+
+    @Inject
+    public MemberViewModel(MemberRepository memberRepository, Gson gson, AccountRepository accountRepository) {
+        this.memberRepository = memberRepository;
+        this.accountRepository = accountRepository;
+        this.gson = gson;
+    }
+
+    public LiveData<Pair<String, String>> getShowWxQRPaymentEvent() {
+        return showWxQRPaymentEvent;
+    }
+
+    public LiveData<Pair<String, String>> getShowAliQRPaymentEvent() {
+        return showAliQRPaymentEvent;
+    }
+
+    public LiveData<Boolean> getShowLoadingEvent() {
+        return showLoadingEvent;
+    }
+
+    public LiveData<?> getShowChoicePayWayDialog() {
+        return showChoicePayWayDialog;
+    }
+
+    public LiveData<String> getServiceContentTxt() {
+        return serviceContentTxt;
+    }
+
+    public LiveData<MemberGoodsBean> getSelectBean() {
+        return selectBean;
+    }
+
+    public void setSelectBean(MemberGoodsBean bean) {
+        selectBean.setValue(bean);
+    }
+
+    public LiveData<List<MemberGoodsBean>> getMemberGoodsList() {
+        return memberGoodsList;
+    }
+
+    public LiveData<List<PayOptionsBean>> getPayWayList() {
+        return payWayList;
+    }
+
+    public List<SuperScenesBean> getSuperScenesBeans() {
+        return superScenesBeans;
+    }
+
+    public LiveData<List<EvaluateBean>> getEvaluateList() {
+        return evaluateList;
+    }
+
+    public LiveData<String> getOnSubscribeSuccessEvent() {
+        return onSubscribeSuccessEvent;
+    }
+
+    public void setMemberType(@MemberType String type) {
+        this.memberType = type;
+        initScenes();
+        initCommentData();
+        refreshMemberDetail();
+    }
+
+    private void initCommentData() {
+        List<EvaluateBean> evaluateBeans = new ArrayList<>();
+        evaluateBeans.add(new EvaluateBean(R.drawable.icon_evaluate_1, "冬季温暖优雅", "我非常满意数据恢复服务的效果。他们专业的团队帮助我成功恢复了丢失的文件,让我感到非常安心和放心。他们高效的工作速度和专业的技术水平让我对他们的服务印象深刻。强烈推荐!"));
+        evaluateBeans.add(new EvaluateBean(R.drawable.icon_evaluate_2, "Starlight99", "我遇到了数据丢失的问题,但幸运的是找到了文件数据恢复大师。他们的技术团队非常专业,通过他们的努力,我成功地恢复了关键文件。他们提供的服务超出了我的期望,我对他们的工作非常满意。如果您需要数据恢复,我强烈推荐选择他们!"));
+        evaluateBeans.add(new EvaluateBean(R.drawable.icon_evaluate_3, "FreeSpirit777", "文件数据恢复大师为我提供了出色的帮助。他们的团队非常耐心地解释了整个恢复过程,并及时与我沟通进展。最重要的是,他们成功地找回了我认为已经永远丢失的数据。感谢他们的专业和高效服务!"));
+        evaluateList.setValue(evaluateBeans);
+    }
+
+    private void initScenes() {
+        superScenesBeans = new ArrayList<>();
+        superScenesBeans.add(new SuperScenesBean(R.drawable.icon_scenes_1, R.string.scenes_message_recover));
+        superScenesBeans.add(new SuperScenesBean(R.drawable.icon_scenes_2, R.string.scenes_friend_recover));
+        superScenesBeans.add(new SuperScenesBean(R.drawable.icon_scenes_3, R.string.scenes_img_recover));
+        superScenesBeans.add(new SuperScenesBean(R.drawable.icon_scenes_4, R.string.scenes_file_recover));
+        superScenesBeans.add(new SuperScenesBean(R.drawable.icon_scenes_5, R.string.scenes_video_recover));
+        superScenesBeans.add(new SuperScenesBean(R.drawable.icon_scenes_6, R.string.scenes_audio_recover));
+        superScenesBeans.add(new SuperScenesBean(R.drawable.icon_scenes_7, R.string.scenes_more, ContextUtil.getContext().getString(R.string.stay_tuned)));
+    }
+
+
+    public void refreshMemberDetail() {
+        if (TextUtils.isEmpty(memberType)) {
+            return;
+        }
+        memberRepository.memberDetail(memberType)
+                .map(memberDetailResponse -> {
+                    List<MemberGoodsBean> list = memberDetailResponse.getList();
+                    if (list != null && !list.isEmpty()) {
+                        for (MemberGoodsBean bean : list) {
+                            if (Objects.equals(bean.getAuths(), MemberType.APP_WX_MESSAGE_RECOVER)) {
+                                bean.setScenesArray(new String[]{"微信好友误删", "微信信息恢复", "导出微信记录", "左滑误删消息"});
+                            } else if (Objects.equals(bean.getAuths(), MemberType.APP_WX_FRIEND_RECOVER)) {
+                                bean.setScenesArray(new String[]{"微信好友被删", "微信好友找回", "恢复恢复好友"});
+                            } else if (Objects.equals(bean.getAuths(), MemberType.APP_IMAGE_RECOVER)) {
+                                bean.setScenesArray(new String[]{"相册误删图片", "手机图片丢失", "手机照片找回"});
+                            } else if (Objects.equals(bean.getAuths(), MemberType.APP_FILE_RECOVER)) {
+                                bean.setScenesArray(new String[]{"手机文件清理", "多类型文件找回", "微信/QQ文件找回"});
+                            } else if (Objects.equals(bean.getAuths(), MemberType.APP_VIDEO_RECOVER)) {
+                                bean.setScenesArray(new String[]{"误删手机视频", "手机视频丢失", "手机视频找回"});
+                            } else if (Objects.equals(bean.getAuths(), MemberType.APP_AUDIO_RECOVER)) {
+                                bean.setScenesArray(new String[]{"误删手机音频", "手机音频丢失", "手机音频找回"});
+                            } else if (Objects.equals(bean.getAuths(), MemberType.APP_IMAGE_CLEAN)) {
+                                bean.setScenesArray(new String[]{"手机图片彻底删除", "选择清除手机图片", "扫描手机图片"});
+                            }
+                        }
+                    }
+                    return memberDetailResponse;
+                })
+                .subscribe(new SingleObserver<MemberDetailResponse>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        addDisposable(d);
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull MemberDetailResponse memberDetailResponse) {
+                        memberGoodsList.setValue(memberDetailResponse.getList());
+                        payWayList.setValue(memberDetailResponse.getPayOptions());
+                        serviceContentTxt.setValue(memberDetailResponse.getDescription());
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+                        e.printStackTrace();
+                    }
+                });
+    }
+
+    public boolean isMember() {
+        return false;
+    }
+
+    public MemberGoodsBean getMostBuyItem() {
+        List<MemberGoodsBean> memberBeans = memberGoodsList.getValue();
+        if (memberBeans == null) {
+            return null;
+        }
+        for (MemberGoodsBean memberBean : memberBeans) {
+            if (Objects.equals(memberBean.getAuths(), MemberType.APP_SUPER_RECOVER)) {
+                return memberBean;
+            }
+        }
+        return null;
+    }
+
+    public void setCurrentSelectedMember(MemberGoodsBean memberBean) {
+        if (Objects.equals(memberBean, selectBean.getValue())) {
+            return;
+        }
+        selectBean.setValue(memberBean);
+    }
+
+    public void onRetainMemberSubscribeClick() {
+        if (!BoxingUtil.boxing(accountRepository.getIsLogin().getValue())) {
+            ToastUtil.show(R.string.no_login, ToastUtil.LENGTH_SHORT);
+            LoginActivity.start(ActivityUtil.getTopActivity());
+            return;
+        }
+        MemberGoodsBean mostBuyItem = getMostBuyItem();
+        if (mostBuyItem == null) {
+            return;
+        }
+        setCurrentSelectedMember(mostBuyItem);
+        //选择支付方式
+        showChoicePayWayDialog.call();
+    }
+
+
+    public void onMemberSubscribeClick() {
+        if (!BoxingUtil.boxing(accountRepository.getIsLogin().getValue())) {
+            ToastUtil.show(R.string.no_login, ToastUtil.LENGTH_SHORT);
+            LoginActivity.start(ActivityUtil.getTopActivity());
+            return;
+        }
+        MemberGoodsBean currentSelected = selectBean.getValue();
+        if (currentSelected == null) {
+            return;
+        }
+        //选择支付方式
+        showChoicePayWayDialog.call();
+    }
+
+
+    public void submitOrder(int payPlatform, int payMethod) {
+        MemberGoodsBean bean = selectBean.getValue();
+        if (bean == null) {
+            return;
+        }
+        memberRepository.requestPayOrder(bean.getId(), payPlatform, payMethod).subscribe(new SingleObserver<MemberPayResponse>() {
+            @Override
+            public void onSubscribe(@NonNull Disposable d) {
+                addDisposable(d);
+                showLoadingEvent.setValue(true);
+            }
+
+            @Override
+            public void onSuccess(@NonNull MemberPayResponse memberPayResponse) {
+                showLoadingEvent.setValue(false);
+                if (payPlatform == 1 && payMethod == 2) {
+                    onWeChatPay(memberPayResponse.getWechatPayPrepayJson(), memberPayResponse.getOutTradeNo());
+                } else if (payPlatform == 4 && payMethod == 2) {
+                    onWeChatScanPay(memberPayResponse.getWechatPayPrepayJson(), memberPayResponse.getOutTradeNo());
+                } else if (payPlatform == 1 && payMethod == 1) {
+                    onAliPay(memberPayResponse.getAlipayOrderString(), memberPayResponse.getOutTradeNo());
+                } else if (payPlatform == 4 && payMethod == 1) {
+                    onAliPayScan(memberPayResponse.getAlipayQrcodeHtml(), memberPayResponse.getOutTradeNo());
+                }
+            }
+
+            @Override
+            public void onError(@NonNull Throwable throwable) {
+                throwable.printStackTrace();
+                showLoadingEvent.setValue(false);
+                if (throwable instanceof RxHttpHandler.ServerErrorException) {
+                    RxHttpHandler.ServerErrorException serverErrorException = (RxHttpHandler.ServerErrorException) throwable;
+                    ToastUtil.show(serverErrorException.getMsg(), ToastUtil.LENGTH_SHORT);
+                } else {
+                    ToastUtil.show(R.string.member_payment_failed, ToastUtil.LENGTH_SHORT);
+                }
+            }
+        });
+    }
+
+    private void onAliPayScan(String s, String orderId) {
+        showAliQRPaymentEvent.setValue(new Pair<>(s, orderId));
+    }
+
+    private void onAliPay(String s, String orderId) {
+        AlipayInfo alipayInfo = new AlipayInfo();
+        alipayInfo.setContent(s);
+        requestSdkPay(alipayInfo, orderId);
+    }
+
+    private void onWeChatScanPay(String s, String orderId) {
+        showWxQRPaymentEvent.setValue(new Pair<>(s, orderId));
+    }
+
+    private void onWeChatPay(String s, String orderId) {
+        try {
+            WechatPaymentSignBean wechatPaymentSignBean = gson.fromJson(s, WechatPaymentSignBean.class);
+            WXpayInfo wXpayInfo = new WXpayInfo();
+            wXpayInfo.setAppid(wechatPaymentSignBean.getAppId());
+            wXpayInfo.setPartnerid(wechatPaymentSignBean.getPartnerId());
+            wXpayInfo.setPrepayid(wechatPaymentSignBean.getPrePayId());
+            wXpayInfo.set_package(wechatPaymentSignBean.getPackageName());
+            wXpayInfo.setNoncestr(wechatPaymentSignBean.getRandomStr());
+            wXpayInfo.setTimestamp(wechatPaymentSignBean.getTimeStamp());
+            wXpayInfo.setSign(wechatPaymentSignBean.getSign());
+            requestSdkPay(wXpayInfo, orderId);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void requestSdkPay(Object payInfo, String orderId) {
+        AgilePay.pay(payInfo, ActivityUtil.getTopActivity(), new AgilePayState() {
+            @Override
+            public void error(int errno, String error) {
+                if (errno == 6001) {
+                    //用户取消支付
+                    return;
+                }
+                ToastUtil.show(R.string.member_payment_failed, ToastUtil.LENGTH_SHORT);
+            }
+
+            @Override
+            public void payError(int errno, String error) {
+                if (errno == 6001) {
+                    //用户取消支付
+                    return;
+                }
+                ToastUtil.show(R.string.member_payment_failed, ToastUtil.LENGTH_SHORT);
+            }
+
+            @Override
+            public void paySuccess(String result) {
+                queryOrderStatus(orderId, true);
+            }
+
+            @Override
+            public void payBefore() {
+
+            }
+        });
+    }
+
+    public @NonNull Disposable queryOrderStatus(String orderId, boolean showLoading) {
+        return memberRepository.getPayStatus(orderId)
+                .doOnSubscribe(disposable -> {
+                    if (showLoading) {
+                        showLoadingEvent.setValue(true);
+                        addDisposable(RxJavaUtil.timer(10, TimeUnit.SECONDS, () -> showLoadingEvent.setValue(false)));
+                    }
+                })
+                .subscribe(aBoolean -> {
+                    showLoadingEvent.setValue(false);
+                    if (BoxingUtil.boxing(aBoolean)) {
+                        onSubscribeSuccessEvent.setValue(orderId);
+                    } else {
+
+                    }
+                }, throwable -> {
+                    throwable.printStackTrace();
+                    showLoadingEvent.setValue(false);
+                });
+    }
+}

+ 57 - 0
app/src/main/java/com/datarecovery/master/module/member/NormalScenesAdapter.java

@@ -0,0 +1,57 @@
+package com.datarecovery.master.module.member;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.datarecovery.master.databinding.ItemNormalScenesBinding;
+
+
+public class NormalScenesAdapter extends RecyclerView.Adapter<NormalScenesAdapter.ViewHolder> {
+
+
+    private String[] list;
+
+    @NonNull
+    @Override
+    public NormalScenesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        Context context = parent.getContext();
+        LayoutInflater layoutInflater = LayoutInflater.from(context);
+        return new ViewHolder(ItemNormalScenesBinding.inflate(layoutInflater, parent, false));
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull NormalScenesAdapter.ViewHolder holder, int position) {
+        holder.bind(list[position]);
+    }
+
+
+    @SuppressLint("NotifyDataSetChanged")
+    public void setData(String[] list) {
+        this.list = list;
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public int getItemCount() {
+        return list == null ? 0 : list.length;
+    }
+
+    public class ViewHolder extends RecyclerView.ViewHolder {
+
+        private final ItemNormalScenesBinding binding;
+
+        public ViewHolder(@NonNull ItemNormalScenesBinding binding) {
+            super(binding.getRoot());
+            this.binding = binding;
+        }
+
+        public void bind(String content) {
+            binding.tvScenesName.setText(content);
+        }
+    }
+}

+ 57 - 0
app/src/main/java/com/datarecovery/master/module/member/SuperScenesAdapter.java

@@ -0,0 +1,57 @@
+package com.datarecovery.master.module.member;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.datarecovery.master.databinding.ItemSuperScenesBinding;
+import com.datarecovery.master.module.member.bean.SuperScenesBean;
+
+import java.util.List;
+
+public class SuperScenesAdapter extends RecyclerView.Adapter<SuperScenesAdapter.ViewHolder> {
+
+    private List<SuperScenesBean> list;
+
+    @NonNull
+    @Override
+    public SuperScenesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        Context context = parent.getContext();
+        LayoutInflater layoutInflater = LayoutInflater.from(context);
+        return new ViewHolder(ItemSuperScenesBinding.inflate(layoutInflater, parent, false));
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull SuperScenesAdapter.ViewHolder holder, int position) {
+        holder.bind(list.get(position));
+    }
+
+    @SuppressLint("NotifyDataSetChanged")
+    public void setData(List<SuperScenesBean> list) {
+        this.list = list;
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public int getItemCount() {
+        return list == null ? 0 : list.size();
+    }
+
+    public class ViewHolder extends RecyclerView.ViewHolder {
+        private final ItemSuperScenesBinding binding;
+
+        public ViewHolder(@NonNull ItemSuperScenesBinding binding) {
+            super(binding.getRoot());
+            this.binding = binding;
+        }
+
+        public void bind(SuperScenesBean superScenesBean) {
+            binding.setBean(superScenesBean);
+        }
+    }
+}

+ 44 - 0
app/src/main/java/com/datarecovery/master/module/member/bean/EvaluateBean.java

@@ -0,0 +1,44 @@
+package com.datarecovery.master.module.member.bean;
+
+import com.google.gson.annotations.SerializedName;
+
+public class EvaluateBean {
+
+    private int icon;
+
+    @SerializedName("name")
+    private String name;
+
+    @SerializedName("content")
+    private String content;
+
+    public int getIcon() {
+        return icon;
+    }
+
+    public void setIcon(int icon) {
+        this.icon = icon;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public EvaluateBean(int icon, String name, String content) {
+        this.icon = icon;
+        this.name = name;
+        this.content = content;
+    }
+}

+ 31 - 0
app/src/main/java/com/datarecovery/master/module/member/bean/SuperScenesBean.java

@@ -0,0 +1,31 @@
+package com.datarecovery.master.module.member.bean;
+
+public class SuperScenesBean {
+
+    private int imgSourceId;
+    private int scenesName;
+    private String scenesExtra;
+
+    public SuperScenesBean(int imgSourceId, int scenesName) {
+        this.imgSourceId = imgSourceId;
+        this.scenesName = scenesName;
+    }
+
+    public SuperScenesBean(int imgSourceId, int scenesName, String scenesExtra) {
+        this.imgSourceId = imgSourceId;
+        this.scenesName = scenesName;
+        this.scenesExtra = scenesExtra;
+    }
+
+    public int getImgSourceId() {
+        return imgSourceId;
+    }
+
+    public int getScenesName() {
+        return scenesName;
+    }
+
+    public String getScenesExtra() {
+        return scenesExtra;
+    }
+}

+ 1 - 1
app/src/main/java/com/datarecovery/master/module/order/OrderViewModel.java

@@ -43,7 +43,7 @@ public class OrderViewModel extends BaseViewModel {
     }
 
     public void refreshOrderPageList() {
-        payRepository.orderPage(0, 100).subscribe(new SingleObserver<OrderPageResponse>() {
+        payRepository.orderPage(0, 200).subscribe(new SingleObserver<OrderPageResponse>() {
             @Override
             public void onSubscribe(@NonNull Disposable d) {
 

+ 62 - 0
app/src/main/java/com/datarecovery/master/module/wxrecover/WeChatRecoverActivity.java

@@ -0,0 +1,62 @@
+package com.datarecovery.master.module.wxrecover;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.atmob.app.lib.base.BaseActivity;
+import com.datarecovery.master.databinding.ActivityWxRecoverBinding;
+import com.gyf.immersionbar.ImmersionBar;
+
+import dagger.hilt.android.AndroidEntryPoint;
+
+@AndroidEntryPoint
+public class WeChatRecoverActivity extends BaseActivity<ActivityWxRecoverBinding> {
+
+
+    private WeChatViewModel weChatViewModel;
+
+    public static void start(Context context) {
+        Intent intent = new Intent(context, WeChatRecoverActivity.class);
+        if (!(context instanceof Activity)) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        initView();
+        initObserver();
+    }
+
+    private void initView() {
+
+    }
+
+    private void initObserver() {
+        weChatViewModel.getFinishEvent().observe(this, o -> finish());
+    }
+
+    @Override
+    protected boolean shouldImmersion() {
+        return true;
+    }
+
+    @Override
+    protected void initViewModel() {
+        super.initViewModel();
+        weChatViewModel = getViewModelProvider().get(WeChatViewModel.class);
+        binding.setWechatViewModel(weChatViewModel);
+    }
+
+    @Override
+    protected void configImmersion(@NonNull ImmersionBar immersionBar) {
+        immersionBar.statusBarDarkFont(true);
+    }
+}

+ 78 - 0
app/src/main/java/com/datarecovery/master/module/wxrecover/WeChatViewModel.java

@@ -0,0 +1,78 @@
+package com.datarecovery.master.module.wxrecover;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.app.lib.livedata.SingleLiveEvent;
+import com.datarecovery.master.R;
+import com.datarecovery.master.data.api.response.FindOrderResponse;
+import com.datarecovery.master.data.repositories.PayRepository;
+import com.datarecovery.master.module.member.MemberType;
+import com.datarecovery.master.utils.ClipboardUtil;
+import com.datarecovery.master.utils.ToastUtil;
+
+import javax.inject.Inject;
+
+import atmob.reactivex.rxjava3.annotations.NonNull;
+import atmob.reactivex.rxjava3.core.SingleObserver;
+import atmob.reactivex.rxjava3.disposables.Disposable;
+import dagger.hilt.android.lifecycle.HiltViewModel;
+
+
+@HiltViewModel
+public class WeChatViewModel extends BaseViewModel {
+
+
+    private final SingleLiveEvent<?> finishEvent = new SingleLiveEvent<>();
+
+    private final MutableLiveData<FindOrderResponse> findOrderDetail = new MutableLiveData<>();
+    private final PayRepository payRepository;
+
+    @Inject
+    public WeChatViewModel(PayRepository payRepository) {
+        this.payRepository = payRepository;
+        findOrder();
+    }
+
+    public LiveData<FindOrderResponse> getFindOrderDetail() {
+        return findOrderDetail;
+    }
+
+    public LiveData<?> getFinishEvent() {
+        return finishEvent;
+    }
+
+
+    public void findOrder() {
+        payRepository.findOrder(new String[]{MemberType.APP_WX_MESSAGE_RECOVER, MemberType.APP_WX_FRIEND_RECOVER, MemberType.APP_SUPER_RECOVER}).subscribe(new SingleObserver<FindOrderResponse>() {
+            @Override
+            public void onSubscribe(@NonNull Disposable d) {
+                addDisposable(d);
+            }
+
+            @Override
+            public void onSuccess(@NonNull FindOrderResponse findOrderResponse) {
+                findOrderDetail.setValue(findOrderResponse);
+            }
+
+            @Override
+            public void onError(@NonNull Throwable e) {
+
+            }
+        });
+    }
+
+    public void onBackClick() {
+        finishEvent.call();
+    }
+
+    public void onCopyLinkClick() {
+        FindOrderResponse value = findOrderDetail.getValue();
+        if (value == null) {
+            return;
+        }
+        ClipboardUtil.copy(value.getTutorialUrl());
+        ToastUtil.show(R.string.copy_success, ToastUtil.LENGTH_SHORT);
+    }
+}

+ 23 - 0
app/src/main/java/com/datarecovery/master/utils/ClipboardUtil.java

@@ -0,0 +1,23 @@
+package com.datarecovery.master.utils;
+
+import android.content.ClipboardManager;
+import android.content.Context;
+
+import com.atmob.common.runtime.ContextUtil;
+
+public class ClipboardUtil {
+    /**
+     * 实现文本复制功能
+     * <p>
+     * add by wangqianzhou
+     *
+     * @param content
+     */
+
+    public static void copy(String content) {
+        // 得到剪贴板管理器
+        Context context = ContextUtil.getContext();
+        ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+        cmb.setText(content.trim());
+    }
+}

+ 63 - 0
app/src/main/java/com/datarecovery/master/utils/GridLayoutItemDecoration.java

@@ -0,0 +1,63 @@
+package com.datarecovery.master.utils;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class GridLayoutItemDecoration extends RecyclerView.ItemDecoration {
+
+    private int spanCount;
+    private float horizontalGapPercent;
+    private float verticalGapPercent;
+
+    private boolean showLastVertical;
+
+    public GridLayoutItemDecoration() {
+
+    }
+
+
+    public GridLayoutItemDecoration(int spanCount, float horizontalGapPercent, float verticalGapPercent) {
+        this.spanCount = spanCount;
+        this.horizontalGapPercent = horizontalGapPercent;
+        this.verticalGapPercent = verticalGapPercent;
+    }
+
+    public void setParam(int spanCount, float horizontalGapPercent, float verticalGapPercent) {
+        this.spanCount = spanCount;
+        this.horizontalGapPercent = horizontalGapPercent;
+        this.verticalGapPercent = verticalGapPercent;
+    }
+
+    public void setShowLastVertical(boolean showLastVertical) {
+        this.showLastVertical = showLastVertical;
+    }
+
+    @Override
+    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+        super.getItemOffsets(outRect, view, parent, state);
+        int horizontalGap = (int) (parent.getMeasuredWidth() * horizontalGapPercent);
+        int verticalGap = (int) (parent.getMeasuredWidth() * verticalGapPercent);
+        int singleGap = horizontalGap * (spanCount - 1) / spanCount;
+        int childAdapterPosition = parent.getChildAdapterPosition(view);
+        int i = childAdapterPosition % spanCount;
+        outRect.top = 0;
+        if (!showLastVertical && parent.getAdapter() != null && parent.getAdapter().getItemCount() - spanCount <= childAdapterPosition) {
+            outRect.bottom = 0;
+        } else {
+            outRect.bottom = verticalGap;
+        }
+        outRect.left = 0;
+        outRect.right = 0;
+        if (i == 0) {
+            outRect.right = singleGap;
+        } else if (i == spanCount - 1) {
+            outRect.left = singleGap;
+        } else {
+            outRect.left = singleGap / 2;
+            outRect.right = singleGap / 2;
+        }
+    }
+}

+ 0 - 16
app/src/main/java/com/datarecovery/master/utils/GridRecoverItemDecoration.java

@@ -58,21 +58,5 @@ public class GridRecoverItemDecoration extends RecyclerView.ItemDecoration {
             outRect.right = 0;
             outRect.bottom = 0;
         }
-//        outRect.top = 0;
-//        if (!showLastVertical && parent.getAdapter() != null && parent.getAdapter().getItemCount() - spanSize <= childAdapterPosition) {
-//            outRect.bottom = 0;
-//        } else {
-//            outRect.bottom = verticalGap;
-//        }
-//        outRect.left = 0;
-//        outRect.right = 0;
-//        if (i == 0) {
-//            outRect.right = singleGap;
-//        } else if (i == spanCount - 1) {
-//            outRect.left = singleGap;
-//        } else {
-//            outRect.left = singleGap / 2;
-//            outRect.right = singleGap / 2;
-//        }
     }
 }

+ 101 - 0
app/src/main/java/com/datarecovery/master/utils/QrCodeUtil.java

@@ -0,0 +1,101 @@
+package com.datarecovery.master.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.drawable.Drawable;
+
+import androidx.annotation.DrawableRes;
+import androidx.core.content.res.ResourcesCompat;
+
+import com.atmob.common.runtime.ContextUtil;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+public class QrCodeUtil {
+    private static final int WHITE = 0xFFFFFFFF;
+
+    private static final int BLACK = 0xFF000000;
+
+    public static Bitmap generateQrCode(String qrCodeData, int size, @DrawableRes int logoRes) throws WriterException {
+        Map<EncodeHintType, Object> hints = null;
+        String encoding = guessAppropriateEncoding(qrCodeData);
+        if (encoding != null) {
+            hints = new EnumMap<>(EncodeHintType.class);
+            hints.put(EncodeHintType.CHARACTER_SET, encoding);
+        }
+        BitMatrix bitMatrix = new MultiFormatWriter().encode(
+                qrCodeData,
+                BarcodeFormat.QR_CODE,
+                size,
+                size,
+                hints
+        );
+        int width = bitMatrix.getWidth();
+        int height = bitMatrix.getHeight();
+        int[] pixels = new int[width * height];
+        int offsetX = -1, offsetY = -1, resultW = -1, resultH = -1;
+        for (int y = 0; y < height; y++) {
+            int offset = y * width;
+            for (int x = 0; x < width; x++) {
+                boolean isBlack = bitMatrix.get(x, y);
+                pixels[offset + x] = isBlack ? BLACK : WHITE;
+                if (isBlack) {
+                    if (offsetX == -1) {
+                        offsetX = x;
+                    }
+                    if (offsetY == -1) {
+                        offsetY = y;
+                    }
+                    if (y == offsetY) {
+                        resultW = x - offsetX;
+                    }
+                    if (x == offsetX) {
+                        resultH = y - offsetY;
+                    }
+                }
+            }
+        }
+        int offset = offsetY * width + offsetX;
+        Bitmap bitmap = Bitmap.createBitmap(resultW, resultH, Bitmap.Config.ARGB_8888);
+        bitmap.setPixels(pixels, offset, width, 0, 0, resultW, resultH);
+
+        if (logoRes != 0) {
+            try {
+                Drawable logoDrawable = ResourcesCompat.getDrawable(ContextUtil.getContext().getResources(), logoRes, null);
+                if (logoDrawable != null) {
+                    Bitmap resultBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+                    Canvas canvas = new Canvas(resultBitmap);
+                    Matrix matrix = new Matrix();
+                    matrix.setScale(size / (float) resultW, size / (float) resultH);
+                    canvas.drawBitmap(bitmap, matrix, null);
+                    int logoSize = (int) (size / 4.3f);
+                    logoDrawable.setBounds(size / 2 - logoSize / 2, size / 2 - logoSize / 2,
+                            size / 2 + logoSize / 2, size / 2 + logoSize / 2);
+                    logoDrawable.draw(canvas);
+                    canvas.setBitmap(null);
+                    bitmap.recycle();
+                    return resultBitmap;
+                }
+            } catch (Exception ignore) {
+            }
+        }
+        return bitmap;
+    }
+
+    private static String guessAppropriateEncoding(CharSequence contents) {
+        // Very crude at the moment
+        for (int i = 0; i < contents.length(); i++) {
+            if (contents.charAt(i) > 0xFF) {
+                return "UTF-8";
+            }
+        }
+        return null;
+    }
+}

+ 28 - 0
app/src/main/java/com/datarecovery/master/widget/UntouchableWebView.java

@@ -0,0 +1,28 @@
+package com.datarecovery.master.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.webkit.WebView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class UntouchableWebView extends WebView {
+    public UntouchableWebView(@NonNull Context context) {
+        super(context);
+    }
+
+    public UntouchableWebView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public UntouchableWebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return false;
+    }
+}

BIN
app/src/main/res/drawable-xxhdpi/bg_member_goods_type_normal.webp


BIN
app/src/main/res/drawable-xxhdpi/bg_member_goods_type_selected.webp


BIN
app/src/main/res/drawable-xxhdpi/bg_member_header_img.webp


BIN
app/src/main/res/drawable-xxhdpi/bg_splash.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_alipay_payment.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_alipay_scan_payment.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_evaluate_1.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_evaluate_2.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_evaluate_3.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_hot.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_member_back.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_member_close.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_member_retention_header.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_scenes_1.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_scenes_2.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_scenes_3.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_scenes_4.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_scenes_5.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_scenes_6.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_scenes_7.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_star.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_wechat_payment.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_wechat_scan_payment.webp


BIN
app/src/main/res/drawable-xxhdpi/icon_wx_recover_pay_success.webp


+ 8 - 0
app/src/main/res/drawable/bg_choice_payment_pay.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/white" />
+    <corners
+        android:topLeftRadius="12dp"
+        android:topRightRadius="12dp" />
+</shape>

+ 8 - 0
app/src/main/res/drawable/bg_dialog_member_retention.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="12dp" />
+    <gradient
+        android:angle="-90"
+        android:endColor="#FFFFFF"
+        android:startColor="#FFFDED" />
+</shape>

+ 7 - 0
app/src/main/res/drawable/bg_member_bottom.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners
+        android:topLeftRadius="12dp"
+        android:topRightRadius="12dp" />
+    <solid android:color="@color/white" />
+</shape>

+ 12 - 0
app/src/main/res/drawable/bg_member_buy_btn.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="8dp" />
+    <stroke
+        android:width="1dp"
+        android:color="#FFD99D" />
+    <gradient
+        android:centerX="0.375"
+        android:centerColor="#FFEEC3"
+        android:endColor="#FFC977"
+        android:startColor="#FFE0A4" />
+</shape>

+ 7 - 0
app/src/main/res/drawable/bg_member_container.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners
+        android:topLeftRadius="20dp"
+        android:topRightRadius="20dp" />
+    <solid android:color="@color/white" />
+</shape>

+ 11 - 0
app/src/main/res/drawable/bg_member_tag.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners
+        android:bottomRightRadius="6dp"
+        android:topLeftRadius="6dp"
+        android:topRightRadius="6dp" />
+
+    <gradient
+        android:endColor="#FF8C19"
+        android:startColor="#FF4006" />
+</shape>

+ 10 - 0
app/src/main/res/drawable/bg_member_title.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners
+        android:bottomLeftRadius="7dp"
+        android:topLeftRadius="7dp" />
+    <gradient
+        android:endColor="#00FDE0AA"
+        android:startColor="#FDE0AA" />
+</shape>

+ 6 - 0
app/src/main/res/drawable/bg_payment_qr_code.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#ffffff" />
+    <corners android:radius="10dp" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/bg_scenes_circle.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#D9D9D9" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/bg_scenes_container.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="8dp" />
+    <solid android:color="#FAF8F7" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/bg_wx_recover.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="8dp" />
+    <solid android:color="@color/white" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/bg_wx_recover_copy.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="11dp" />
+    <solid android:color="#EFEFEF" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/bg_wx_recover_desc.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="8dp" />
+    <solid android:color="#FBFBFB" />
+</shape>

+ 286 - 0
app/src/main/res/layout/activity_member.xml

@@ -0,0 +1,286 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="memberViewModel"
+            type="com.datarecovery.master.module.member.MemberViewModel" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+
+        <androidx.core.widget.NestedScrollView
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintBottom_toTopOf="@+id/view_bottom"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <androidx.constraintlayout.widget.ConstraintLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:src="@drawable/bg_member_header_img"
+                    app:layout_constraintDimensionRatio="1080:789"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <Space
+                    android:id="@+id/space1"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    app:layout_constraintDimensionRatio="360:187"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <androidx.constraintlayout.widget.ConstraintLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:background="@drawable/bg_member_container"
+                    app:layout_constraintTop_toBottomOf="@+id/space1">
+
+                    <Space
+                        android:id="@+id/space_detail_top"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        app:layout_constraintDimensionRatio="360:21"
+                        app:layout_constraintTop_toTopOf="parent" />
+
+                    <View
+                        android:id="@+id/icon_member_benefit"
+                        android:layout_width="0dp"
+                        android:layout_height="0dp"
+                        android:layout_marginBottom="-2dp"
+                        android:background="@drawable/bg_member_title"
+                        app:layout_constraintBottom_toBottomOf="@+id/member_func_title"
+                        app:layout_constraintDimensionRatio="64:8"
+                        app:layout_constraintLeft_toLeftOf="@+id/member_func_title"
+                        app:layout_constraintWidth_percent="0.1777777777777778" />
+
+
+                    <TextView
+                        android:id="@+id/member_func_title"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+                        android:text="@string/member_func_title"
+                        android:textColor="#202020"
+                        android:textSize="16sp"
+                        android:textStyle="bold"
+                        app:layout_constraintStart_toStartOf="parent"
+                        app:layout_constraintTop_toBottomOf="@+id/space_detail_top" />
+
+                    <Space
+                        android:id="@+id/space2"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        app:layout_constraintDimensionRatio="360:14"
+                        app:layout_constraintTop_toBottomOf="@+id/member_func_title" />
+
+                    <androidx.recyclerview.widget.RecyclerView
+                        android:id="@+id/member_detail_list"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:paddingHorizontal="@dimen/app_common_page_horizontal_padding"
+                        app:layout_constraintTop_toBottomOf="@id/space2"
+                        tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+                        tools:listitem="@layout/item_member_goods"
+                        tools:orientation="horizontal" />
+
+                    <Space
+                        android:id="@+id/space3"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        app:layout_constraintDimensionRatio="360:20"
+                        app:layout_constraintTop_toBottomOf="@+id/member_detail_list" />
+
+                    <TextView
+                        android:id="@+id/member_scenes_title"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@{memberViewModel.selectBean.superRecover ? @string/member_super_title : @string/member_scenes_title }"
+                        android:textColor="#202020"
+                        android:textSize="14sp"
+                        android:textStyle="bold"
+                        app:layout_constraintLeft_toLeftOf="@+id/member_func_title"
+                        app:layout_constraintTop_toBottomOf="@+id/space3"
+                        tools:text="使用场景" />
+
+                    <Space
+                        android:id="@+id/space4"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        app:layout_constraintDimensionRatio="360:12"
+                        app:layout_constraintTop_toBottomOf="@+id/member_scenes_title" />
+
+
+                    <androidx.recyclerview.widget.RecyclerView
+                        android:id="@+id/scenes_ry_view"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginHorizontal="16dp"
+                        android:background="@{memberViewModel.selectBean.superRecover ? null: @drawable/bg_scenes_container}"
+                        android:overScrollMode="never"
+                        android:padding="8dp"
+                        app:layout_constraintTop_toBottomOf="@+id/space4" />
+
+                    <Space
+                        android:id="@+id/space5"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        app:layout_constraintDimensionRatio="360:20"
+                        app:layout_constraintTop_toBottomOf="@+id/scenes_ry_view" />
+
+                    <View
+                        android:id="@+id/v_divider"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        android:background="#F9FAFC"
+                        app:layout_constraintDimensionRatio="360:8"
+                        app:layout_constraintTop_toBottomOf="@+id/space5" />
+
+                    <Space
+                        android:id="@+id/space6"
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        app:layout_constraintDimensionRatio="360:20"
+                        app:layout_constraintTop_toBottomOf="@+id/v_divider" />
+
+                    <View
+                        android:id="@+id/icon_user_evaluate"
+                        android:layout_width="0dp"
+                        android:layout_height="0dp"
+                        android:layout_marginBottom="-2dp"
+                        android:background="@drawable/bg_member_title"
+                        app:layout_constraintBottom_toBottomOf="@+id/member_user_evaluate_title"
+                        app:layout_constraintDimensionRatio="64:8"
+                        app:layout_constraintLeft_toLeftOf="@+id/member_user_evaluate_title"
+                        app:layout_constraintWidth_percent="0.1777777777777778" />
+
+
+                    <TextView
+                        android:id="@+id/member_user_evaluate_title"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+                        android:text="@string/member_user_evaluate"
+                        android:textColor="#202020"
+                        android:textSize="16sp"
+                        android:textStyle="bold"
+                        app:layout_constraintStart_toStartOf="parent"
+                        app:layout_constraintTop_toBottomOf="@+id/space6" />
+
+                    <androidx.recyclerview.widget.RecyclerView
+                        android:id="@+id/user_evaluate_ry_view"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:overScrollMode="never"
+                        app:layout_constraintTop_toBottomOf="@+id/icon_user_evaluate" />
+
+                    <TextView
+                        android:id="@+id/member_service_content"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/member_service_description"
+                        android:textColor="#404040"
+                        android:textSize="14sp"
+                        android:textStyle="bold"
+                        app:layout_constraintStart_toStartOf="@+id/member_scenes_title"
+                        app:layout_constraintTop_toBottomOf="@+id/user_evaluate_ry_view" />
+
+                    <TextView
+                        android:id="@+id/member_service_content_txt"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
+                        android:layout_marginTop="8dp"
+                        android:text="@{memberViewModel.getServiceContentTxt}"
+                        app:layout_constraintTop_toBottomOf="@+id/member_service_content"
+                        tools:text="1.根据相关法律对个人隐私保护的规定,需购买会员才可使用,请在购买套餐前仔细阅读我们的《隐私协议》,您在付费会员服务时必须完全,严格的遵守本服务协议的规则。
+2.会员服务说明:您购买的任何会员服务购买成功后一年有效,但请注意,您如果先买了单个功能恢复,后续又买了全部功能恢复,那么您之前购买的单个功能恢复则无法退款。
+3.若您在支付过程中遇到问题,无法支付或支付失败,请先检查自己账户内的余额,若还是存在支付问题请联系客服解决。
+4.在线客服工作时间7*18小时
+5.本产品功能只作为本人数据恢复,请用于合法用途经发现违法使用则立即封停账号并视情节严重与否追究法律。
+6.付费会员服务仅供您自行使用,使用过程中需要电脑配合,可根据详细的恢复教程,通过获取的授权码和软件自行操作,使用过程中遇到问题可以联系官方客服解决
+7.我们的软件会尽可能为您恢复出数据中可能恢复的记录,越早操作恢复概率越高。
+8.支付后可开具增值税发票(纸质发票,邮寄到付)" />
+
+                    <Space
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        app:layout_constraintDimensionRatio="360:37"
+                        app:layout_constraintTop_toBottomOf="@+id/member_service_content_txt" />
+
+
+                </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+            </androidx.constraintlayout.widget.ConstraintLayout>
+
+        </androidx.core.widget.NestedScrollView>
+
+        <androidx.appcompat.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:layout_constraintTop_toTopOf="parent">
+
+
+            <ImageView
+                android:id="@+id/icon_back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="start"
+                android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+                android:background="?android:selectableItemBackgroundBorderless"
+                android:src="@drawable/icon_member_back" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/member_action_title"
+                android:textColor="#202020"
+                android:textSize="17sp"
+                android:textStyle="bold" />
+
+        </androidx.appcompat.widget.Toolbar>
+
+        <View
+            android:id="@+id/view_bottom"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_member_bottom"
+            android:elevation="10dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="360:86" />
+
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_member_buy_btn"
+            android:elevation="10dp"
+            android:gravity="center"
+            android:text="@string/member_buy"
+            android:textColor="#6A3420"
+            android:onClick="@{() -> memberViewModel.onMemberSubscribeClick()}"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@+id/view_bottom"
+            app:layout_constraintDimensionRatio="328:48"
+            app:layout_constraintEnd_toEndOf="@+id/view_bottom"
+            app:layout_constraintStart_toStartOf="@+id/view_bottom"
+            app:layout_constraintTop_toTopOf="@+id/view_bottom"
+            app:layout_constraintVertical_bias="0.3684210526315789"
+            app:layout_constraintWidth_percent="0.9111111111111111" />
+
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 297 - 0
app/src/main/res/layout/activity_wx_recover.xml

@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="wechatViewModel"
+            type="com.datarecovery.master.module.wxrecover.WeChatViewModel" />
+
+        <import type="com.atmob.common.ui.SizeUtil" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#EFEFEF">
+
+
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:src="@drawable/bg_mine_background"
+            app:layout_constraintDimensionRatio="1080:648"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <Space
+            android:id="@+id/space_status_bar"
+            android:layout_width="match_parent"
+            android:layout_height="@{SizeUtil.getStatusBarHeight(), default=@dimen/app_status_bar_height}"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <Space
+            android:id="@+id/space1"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:22"
+            app:layout_constraintTop_toBottomOf="@+id/space_status_bar" />
+
+        <ImageView
+            android:id="@+id/iv_back"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:onClick="@{()->wechatViewModel.onBackClick()}"
+            android:src="@drawable/icon_back"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/space1"
+            app:layout_constraintWidth_percent="0.0666666666666667" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/wx_recover_title"
+            android:textColor="#202020"
+            android:textSize="17sp"
+            app:layout_constraintBottom_toBottomOf="@+id/iv_back"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/iv_back" />
+
+        <Space
+            android:id="@+id/space2"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:15"
+            app:layout_constraintTop_toBottomOf="@+id/iv_back" />
+
+        <ImageView
+            android:id="@+id/iv_wx_recover_pay_success"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:src="@drawable/icon_wx_recover_pay_success"
+            app:layout_constraintDimensionRatio="110:60"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/space2"
+            app:layout_constraintWidth_percent="0.3055555555555556" />
+
+        <TextView
+            android:id="@+id/tv_wx_recover_pay_success"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="6dp"
+            android:text="@string/wx_recover_pay_success"
+            android:textColor="#202020"
+            android:textSize="20sp"
+            android:textStyle="bold"
+            app:layout_constraintEnd_toEndOf="@+id/iv_wx_recover_pay_success"
+            app:layout_constraintStart_toStartOf="@+id/iv_wx_recover_pay_success"
+            app:layout_constraintTop_toBottomOf="@+id/iv_wx_recover_pay_success" />
+
+        <Space
+            android:id="@+id/space3"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:14"
+            app:layout_constraintTop_toBottomOf="@+id/tv_wx_recover_pay_success" />
+
+        <Space
+            android:id="@+id/space4"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:16"
+            app:layout_constraintTop_toBottomOf="@+id/space3" />
+
+        <View
+            android:id="@+id/v_order_bg"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
+            android:background="@drawable/bg_wx_recover"
+            app:layout_constraintBottom_toBottomOf="@+id/space7"
+            app:layout_constraintTop_toTopOf="@id/space4" />
+
+        <TextView
+            android:id="@+id/tv_order_detail"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            android:text="@string/wx_recover_order_detail"
+            android:textColor="#202020"
+            android:textSize="14sp"
+            android:textStyle="bold"
+            app:layout_constraintStart_toStartOf="@+id/v_order_bg"
+            app:layout_constraintTop_toBottomOf="@+id/space4" />
+
+        <View
+            android:id="@+id/v_order_line"
+            android:layout_width="0dp"
+            android:layout_height="1dp"
+            android:layout_marginTop="4dp"
+            android:background="#F5F5F5"
+            app:layout_constraintStart_toStartOf="@id/tv_order_detail"
+            app:layout_constraintTop_toBottomOf="@+id/tv_order_detail"
+            app:layout_constraintWidth_percent="0.8222222222222222" />
+
+        <TextView
+            android:id="@+id/tv_order_no"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="9dp"
+            android:text="@string/wx_recover_order_no"
+            android:textColor="#404040"
+            android:textSize="14sp"
+            app:layout_constraintLeft_toLeftOf="@+id/tv_order_detail"
+            app:layout_constraintTop_toBottomOf="@+id/v_order_line" />
+
+        <TextView
+            android:id="@+id/tv_order_no_copy"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="12dp"
+            android:background="@drawable/bg_wx_recover_copy"
+            android:paddingHorizontal="8dp"
+            android:paddingVertical="1dp"
+            android:text="@string/wx_recover_copy"
+            android:textColor="#404040"
+            android:textSize="12sp"
+            app:layout_constraintBottom_toBottomOf="@+id/tv_order_no"
+            app:layout_constraintEnd_toEndOf="@id/v_order_bg"
+            app:layout_constraintTop_toTopOf="@+id/tv_order_no" />
+
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="6dp"
+            android:text="@{wechatViewModel.findOrderDetail.outTradeNo}"
+            android:textColor="#A7A7A7"
+            android:textSize="14sp"
+            app:layout_constraintBottom_toBottomOf="@+id/tv_order_no"
+            app:layout_constraintEnd_toStartOf="@+id/tv_order_no_copy"
+            app:layout_constraintTop_toTopOf="@id/tv_order_no"
+            tools:text="1541988181058187" />
+
+        <Space
+            android:id="@+id/space5"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:20"
+            app:layout_constraintTop_toBottomOf="@+id/tv_order_no" />
+
+        <TextView
+            android:id="@+id/tv_auth_code"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="9dp"
+            android:text="@string/wx_recover_auth_code"
+            android:textColor="#404040"
+            android:textSize="14sp"
+            app:layout_constraintLeft_toLeftOf="@+id/tv_order_detail"
+            app:layout_constraintTop_toBottomOf="@+id/space5" />
+
+        <TextView
+            android:id="@+id/tv_auth_code_copy"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="12dp"
+            android:background="@drawable/bg_wx_recover_copy"
+            android:paddingHorizontal="8dp"
+            android:paddingVertical="1dp"
+            android:text="@string/wx_recover_copy"
+            android:textColor="#404040"
+            android:textSize="12sp"
+            app:layout_constraintBottom_toBottomOf="@+id/tv_auth_code"
+            app:layout_constraintEnd_toEndOf="@id/v_order_bg"
+            app:layout_constraintTop_toTopOf="@+id/tv_auth_code" />
+
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="6dp"
+            android:text="@{wechatViewModel.findOrderDetail.authCode}"
+            android:textColor="#A7A7A7"
+            android:textSize="14sp"
+            app:layout_constraintBottom_toBottomOf="@+id/tv_auth_code"
+            app:layout_constraintEnd_toStartOf="@+id/tv_order_no_copy"
+            app:layout_constraintTop_toTopOf="@id/tv_auth_code"
+            tools:text="15419881810" />
+
+
+        <Space
+            android:id="@+id/space6"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:20"
+            app:layout_constraintTop_toBottomOf="@+id/tv_auth_code" />
+
+
+        <LinearLayout
+            android:id="@+id/ll_wx_recover_desc"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="12dp"
+            android:background="@drawable/bg_wx_recover_desc"
+            android:orientation="vertical"
+            android:padding="12dp"
+            app:layout_constraintEnd_toEndOf="@+id/v_order_bg"
+            app:layout_constraintStart_toStartOf="@+id/v_order_bg"
+            app:layout_constraintTop_toBottomOf="@+id/space6">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/wx_recover_tutorial"
+                android:textColor="#404040"
+                android:textSize="12sp"
+                android:textStyle="bold" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="6dp"
+                android:text="@string/wx_recover_tutorial_content" />
+        </LinearLayout>
+
+        <Space
+            android:id="@+id/space7"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:15"
+            app:layout_constraintTop_toBottomOf="@+id/ll_wx_recover_desc" />
+
+
+        <View
+            android:id="@+id/v_bottom_bg"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:background="@color/white"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="360:72" />
+
+        <TextView
+            android:onClick="@{()-> wechatViewModel.onCopyLinkClick()}"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_common_btn"
+            android:gravity="center"
+            android:text="@string/wx_recover_copy_link"
+            android:textColor="@color/white"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@+id/v_bottom_bg"
+            app:layout_constraintDimensionRatio="328:44"
+            app:layout_constraintEnd_toEndOf="@+id/v_bottom_bg"
+            app:layout_constraintStart_toStartOf="@+id/v_bottom_bg"
+            app:layout_constraintTop_toTopOf="@+id/v_bottom_bg"
+            app:layout_constraintWidth_percent="0.9111111111111111" />
+
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 67 - 0
app/src/main/res/layout/dialog_alipay_qr_code.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout>
+
+    <data>
+
+        <variable
+            name="onCloseClickListener"
+            type="android.view.View.OnClickListener" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        tools:background="@color/black45">
+
+        <View
+            android:id="@+id/alipay_qr_code_bg"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_payment_qr_code"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_bias="0.3534090909090909"
+            app:layout_constraintWidth_percent="0.8611111111111111" />
+
+        <com.datarecovery.master.widget.UntouchableWebView
+            android:id="@+id/alipay_qr_code_web_view"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:overScrollMode="never"
+            android:scrollbars="none"
+            app:layout_constraintBottom_toBottomOf="@id/alipay_qr_code_bg"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintLeft_toLeftOf="@id/alipay_qr_code_bg"
+            app:layout_constraintRight_toRightOf="@id/alipay_qr_code_bg"
+            app:layout_constraintTop_toTopOf="@id/alipay_qr_code_bg"
+            app:layout_constraintVertical_bias="0.3"
+            app:layout_constraintWidth_percent="0.6388888888888889" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/alipay_qr_code_tips"
+            android:textColor="@color/black"
+            android:textSize="14sp"
+            app:layout_constraintBottom_toBottomOf="@id/alipay_qr_code_bg"
+            app:layout_constraintLeft_toLeftOf="@id/alipay_qr_code_bg"
+            app:layout_constraintRight_toRightOf="@id/alipay_qr_code_bg"
+            app:layout_constraintTop_toBottomOf="@id/alipay_qr_code_web_view" />
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:onClickListener="@{onCloseClickListener}"
+            android:src="@drawable/icon_member_close"
+            app:layout_constraintLeft_toLeftOf="@id/alipay_qr_code_bg"
+            app:layout_constraintRight_toRightOf="@id/alipay_qr_code_bg"
+            app:layout_constraintTop_toBottomOf="@id/alipay_qr_code_bg"
+            app:tint="@color/white" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 109 - 0
app/src/main/res/layout/dialog_choose_payment_way.xml

@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="onCloseClickListener"
+            type="android.view.View.OnClickListener" />
+
+        <variable
+            name="onPayClickListener"
+            type="android.view.View.OnClickListener" />
+
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <View
+            android:id="@+id/bg_payment_way_content"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_choice_payment_pay"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <Space
+            android:id="@+id/space1"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:20"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:id="@+id/title_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+            android:text="@string/pay_way"
+            android:textColor="#202020"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/space1" />
+
+        <Space
+            android:id="@+id/space2"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:14"
+            app:layout_constraintTop_toBottomOf="@+id/title_text" />
+
+        <LinearLayout
+            android:id="@+id/ll_pay"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            app:layout_constraintTop_toBottomOf="@+id/space2" />
+
+        <Space
+            android:id="@+id/space3"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:23"
+            app:layout_constraintTop_toBottomOf="@+id/ll_pay" />
+
+
+        <TextView
+            android:id="@+id/member_payment_btn"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
+            android:layout_marginTop="12dp"
+            android:layout_marginBottom="25dp"
+            android:background="@drawable/bg_member_buy_btn"
+            android:gravity="center"
+            android:onClickListener="@{onPayClickListener}"
+            android:text="@string/member_pay_right_now"
+            android:textColor="#6A3420"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            app:layout_constraintDimensionRatio="328:48"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/space3" />
+
+        <Space
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:16"
+            app:layout_constraintTop_toBottomOf="@+id/member_payment_btn" />
+
+        <ImageView
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginTop="@dimen/app_common_page_horizontal_padding"
+            android:layout_marginEnd="@dimen/app_common_page_horizontal_padding"
+            android:onClickListener="@{onCloseClickListener}"
+            android:src="@drawable/icon_member_close"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintWidth_percent="0.0666666666666667" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 110 - 0
app/src/main/res/layout/dialog_member_retention.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="onCloseClickListener"
+            type="android.view.View.OnClickListener" />
+
+        <variable
+            name="onContinueClickListener"
+            type="android.view.View.OnClickListener" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        tools:background="@color/black20">
+
+        <ImageView
+            android:id="@+id/bg_dialog_member_retention"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_dialog_member_retention"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="280:244"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_bias="0.5833333333333333"
+            app:layout_constraintWidth_percent="0.7777777777777778" />
+
+        <Space
+            android:id="@+id/space1"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintBottom_toTopOf="@id/bg_dialog_member_retention"
+            app:layout_constraintDimensionRatio="360:30" />
+
+        <ImageView
+            android:id="@+id/icon_retention_describe"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:src="@drawable/icon_member_retention_header"
+            app:layout_constraintDimensionRatio="123:100"
+            app:layout_constraintEnd_toEndOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintStart_toStartOf="@id/bg_dialog_member_retention"
+            app:layout_constraintTop_toTopOf="@+id/space1"
+            app:layout_constraintWidth_percent="0.3416666666666667" />
+
+        <TextView
+            android:id="@+id/retention_give_up_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:text="@string/retention_give_up_title"
+            android:textColor="#6A3420"
+            android:textSize="20sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintLeft_toLeftOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintRight_toRightOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintTop_toTopOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintVertical_bias="0.3906976744186047" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:text="@string/retention_give_up_text"
+            android:textColor="#949494"
+            android:textSize="14sp"
+            app:layout_constraintEnd_toEndOf="@id/bg_dialog_member_retention"
+            app:layout_constraintStart_toStartOf="@id/bg_dialog_member_retention"
+            app:layout_constraintTop_toBottomOf="@+id/retention_give_up_text" />
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginTop="24dp"
+            android:background="@drawable/bg_member_buy_btn"
+            android:gravity="center"
+            android:onClickListener="@{onContinueClickListener}"
+            android:text="@string/retention_continue_text"
+            android:textColor="#6A3420"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintDimensionRatio="232:48"
+            app:layout_constraintLeft_toLeftOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintRight_toRightOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintTop_toTopOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintVertical_bias="0.8775510204081633"
+            app:layout_constraintWidth_percent="0.6444444444444444" />
+
+        <ImageView
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_margin="12dp"
+            android:onClickListener="@{onCloseClickListener}"
+            android:src="@drawable/icon_member_close"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintEnd_toEndOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintTop_toTopOf="@+id/bg_dialog_member_retention"
+            app:layout_constraintWidth_percent="0.0666666666666667" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 66 - 0
app/src/main/res/layout/dialog_wechat_pay_qr_code.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout>
+
+    <data>
+
+        <variable
+            name="onCloseClickListener"
+            type="android.view.View.OnClickListener" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        tools:background="@color/black45">
+
+        <View
+            android:id="@+id/wechat_pay_qr_code_bg"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_payment_qr_code"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_bias="0.3534090909090909"
+            app:layout_constraintWidth_percent="0.8611111111111111" />
+
+        <ImageView
+            android:id="@+id/wechat_pay_qr_code"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            tools:background="@color/black30"
+            app:layout_constraintBottom_toBottomOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintLeft_toLeftOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintRight_toRightOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintTop_toTopOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintVertical_bias="0.3"
+            app:layout_constraintWidth_percent="0.6388888888888889" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/wechat_pay_qr_code_tips"
+            android:textColor="@color/black"
+            android:textSize="14sp"
+            app:layout_constraintBottom_toBottomOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintLeft_toLeftOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintRight_toRightOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintTop_toBottomOf="@id/wechat_pay_qr_code" />
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:onClickListener="@{onCloseClickListener}"
+            android:src="@drawable/icon_member_close"
+            app:layout_constraintLeft_toLeftOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintRight_toRightOf="@id/wechat_pay_qr_code_bg"
+            app:layout_constraintTop_toBottomOf="@id/wechat_pay_qr_code_bg"
+            app:tint="@color/white" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 2 - 2
app/src/main/res/layout/fragment_example.xml

@@ -43,10 +43,10 @@
             android:layout_height="0dp"
             android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
             android:src="@drawable/icon_example"
-            app:layout_constraintDimensionRatio="216:60"
+            app:layout_constraintDimensionRatio="246:60"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/space1"
-            app:layout_constraintWidth_percent="0.2" />
+            app:layout_constraintWidth_percent="0.2277777777777778" />
 
         <Space
             android:id="@+id/space2"

+ 1 - 1
app/src/main/res/layout/fragment_order.xml

@@ -46,7 +46,7 @@
             app:layout_constraintDimensionRatio="246:60"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/space1"
-            app:layout_constraintWidth_percent="0.2" />
+            app:layout_constraintWidth_percent="0.2277777777777778" />
 
         <Space
             android:id="@+id/space2"

+ 85 - 0
app/src/main/res/layout/item_member_evaluate.xml

@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="evaluateBean"
+            type="com.datarecovery.master.module.member.bean.EvaluateBean" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <Space
+            android:id="@+id/space_top"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:12"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <ImageView
+            android:id="@+id/icon_member_evaluate_header"
+            imageRes="@{evaluateBean.icon}"
+            radius="@{100}"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/space_top"
+            app:layout_constraintWidth_percent="0.0888888888888889"
+            tools:src="@drawable/icon_evaluate_1" />
+
+        <TextView
+            android:id="@+id/member_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:layout_marginTop="4dp"
+            android:text="@{evaluateBean.name}"
+            android:textColor="#202020"
+            android:textSize="15sp"
+            android:textStyle="bold"
+            app:layout_constraintLeft_toRightOf="@+id/icon_member_evaluate_header"
+            app:layout_constraintTop_toTopOf="@+id/icon_member_evaluate_header"
+            tools:text="冬季温暖优雅" />
+
+        <ImageView
+            android:id="@+id/iv_star"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginTop="4dp"
+            android:src="@drawable/icon_star"
+            app:layout_constraintDimensionRatio="249:42"
+            app:layout_constraintStart_toStartOf="@+id/member_name"
+            app:layout_constraintTop_toBottomOf="@+id/member_name"
+            app:layout_constraintWidth_percent="0.2305555555555556" />
+
+        <TextView
+            android:id="@+id/member_evaluate_content"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_marginEnd="@dimen/app_common_page_horizontal_padding"
+            android:text="@{evaluateBean.content}"
+            android:textColor="#404040"
+            android:textSize="15sp"
+            app:layout_constraintLeft_toLeftOf="@+id/member_name"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/iv_star"
+            tools:text="我非常满意数据恢复服务的效果。他们专业的团队帮助我成功恢复了丢失的文件,让我感到非常安心和放心。他们高效的工作速度和专业的技术水平让我对他们的服务印象深刻。强烈推荐!" />
+
+        <Space
+            android:id="@+id/space_bottom"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="360:21"
+            app:layout_constraintTop_toBottomOf="@+id/member_evaluate_content" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</layout>

+ 132 - 0
app/src/main/res/layout/item_member_goods.xml

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="goodsBean"
+            type="com.datarecovery.master.data.api.bean.MemberGoodsBean" />
+
+        <import type="com.atmob.common.ui.SizeUtil" />
+
+        <import type="com.atmob.common.text.TextUtil" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="12dp">
+
+
+        <ImageView
+            android:id="@+id/iv_bg"
+            imageDraw="@{goodsBean.select ? @drawable/bg_member_goods_type_selected : @drawable/bg_member_goods_type_normal}"
+            android:layout_width="@{(float)SizeUtil.getScreenWidth() * 0.4388888888888889f, default=wrap_content}"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="474:426"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/space1"
+            tools:src="@drawable/bg_member_goods_type_normal" />
+
+        <Space
+            android:id="@+id/space1"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            app:layout_constraintBottom_toBottomOf="@+id/tv_member_buy_tag"
+            app:layout_constraintStart_toStartOf="@+id/tv_member_buy_tag"
+            app:layout_constraintTop_toTopOf="@+id/tv_member_buy_tag" />
+
+        <TextView
+            android:id="@+id/tv_member_buy_tag"
+            isInvisible="@{!goodsBean.popular}"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/bg_member_tag"
+            android:drawablePadding="2dp"
+            android:paddingHorizontal="10dp"
+            android:paddingVertical="4dp"
+            android:text="@string/member_buy_tag_txt"
+            android:textColor="@color/white"
+            android:textSize="12sp"
+            android:textStyle="bold"
+            app:drawableStartCompat="@drawable/icon_hot"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@{goodsBean.name}"
+            android:textColor="#404040"
+            android:textSize="15sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@id/iv_bg"
+            app:layout_constraintEnd_toEndOf="@+id/iv_bg"
+            app:layout_constraintStart_toStartOf="@id/iv_bg"
+            app:layout_constraintTop_toTopOf="@id/iv_bg"
+            app:layout_constraintVertical_bias="0.1416666666666667"
+            tools:text="微信信息恢复" />
+
+        <TextView
+            android:id="@+id/tv_member_buy_price_unit"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/rmb"
+            android:textColor="@{goodsBean.select ? @color/member_buy_price_text_selected : @color/member_buy_price_text_normal}"
+            android:textSize="20sp"
+            android:textStyle="bold"
+            app:layout_constraintBaseline_toBaselineOf="@id/tv_member_buy_price"
+            app:layout_constraintHorizontal_chainStyle="packed"
+            app:layout_constraintLeft_toLeftOf="@+id/iv_bg"
+            app:layout_constraintRight_toLeftOf="@+id/tv_member_buy_price"
+            tools:textColor="#404040" />
+
+        <TextView
+            android:id="@+id/tv_member_buy_price"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@{TextUtil.formatFloatWithout0End(goodsBean.originalAmount, 1)}"
+            android:textColor="@{goodsBean.select ? @color/member_buy_price_text_selected : @color/member_buy_price_text_normal}"
+            android:textSize="40sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@id/iv_bg"
+            app:layout_constraintLeft_toRightOf="@+id/tv_member_buy_price_unit"
+            app:layout_constraintRight_toRightOf="@+id/iv_bg"
+            app:layout_constraintTop_toTopOf="@id/iv_bg"
+            app:layout_constraintVertical_bias="0.4526315789473684"
+            tools:text="66"
+            tools:textColor="#404040" />
+
+        <TextView
+            deleteLine="@{Boolean.TRUE}"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@{@string/member_price(TextUtil.formatFloatWithout0End(goodsBean.originalAmount, 1))}"
+            android:textColor="@{goodsBean.select ? @color/member_original_price_text_selected : @color/member_original_price_text_normal}"
+            android:textSize="12sp"
+            app:layout_constraintBottom_toBottomOf="@id/iv_bg"
+            app:layout_constraintEnd_toEndOf="@id/iv_bg"
+            app:layout_constraintStart_toStartOf="@id/iv_bg"
+            app:layout_constraintTop_toTopOf="@id/iv_bg"
+            app:layout_constraintVertical_bias="0.752"
+            tools:text="¥299" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@{goodsBean.description}"
+            android:textColor="#7C4B00"
+            android:textSize="12sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@id/iv_bg"
+            app:layout_constraintEnd_toEndOf="@id/iv_bg"
+            app:layout_constraintStart_toStartOf="@id/iv_bg"
+            app:layout_constraintTop_toTopOf="@id/iv_bg"
+            app:layout_constraintVertical_bias="0.936"
+            tools:text="单个功能恢复" />
+
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 23 - 0
app/src/main/res/layout/item_normal_scenes.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:orientation="horizontal">
+
+    <View
+        android:layout_width="8dp"
+        android:layout_height="8dp"
+        android:background="@drawable/bg_scenes_circle" />
+
+    <TextView
+        android:id="@+id/tv_scenes_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="5dp"
+        android:textColor="#404040"
+        android:textSize="14sp"
+        tools:text="微信好友误删" />
+
+</LinearLayout>

+ 63 - 0
app/src/main/res/layout/item_super_scenes.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="bean"
+            type="com.datarecovery.master.module.member.bean.SuperScenesBean" />
+
+        <import type="com.atmob.common.ui.SizeUtil" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/iv_icon"
+            imageRes="@{bean.imgSourceId}"
+            android:layout_width="@{(float)SizeUtil.getScreenWidth() * 0.1111111111111111f, default=wrap_content}"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:src="@drawable/icon_scenes_1" />
+
+        <Space
+            android:id="@+id/space"
+            isGone="@{bean.scenesExtra != null}"
+            android:layout_width="match_parent"
+            android:layout_height="6dp"
+            app:layout_constraintTop_toBottomOf="@+id/iv_icon" />
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@{bean.scenesName}"
+            android:textColor="#202020"
+            android:textSize="13sp"
+            app:layout_constraintEnd_toEndOf="@+id/iv_icon"
+            app:layout_constraintStart_toStartOf="@+id/iv_icon"
+            app:layout_constraintTop_toBottomOf="@+id/space"
+            tools:text="信息恢复" />
+
+        <TextView
+            isGone="@{bean.scenesExtra == null}"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="@{bean.scenesExtra}"
+            android:textColor="#A7A7A7"
+            android:textSize="10sp"
+            app:layout_constraintEnd_toEndOf="@+id/iv_icon"
+            app:layout_constraintStart_toStartOf="@id/iv_icon"
+            app:layout_constraintTop_toBottomOf="@+id/tv_title"
+            tools:text="敬请期待" />
+
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 84 - 0
app/src/main/res/layout/layout_item_payment_way.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <variable
+            name="paymentWayName"
+            type="String" />
+
+        <variable
+            name="paymentWayIcon"
+            type="android.graphics.drawable.Drawable" />
+
+        <variable
+            name="position"
+            type="Integer" />
+
+        <variable
+            name="selectedPosition"
+            type="androidx.lifecycle.LiveData&lt;Integer>" />
+
+    </data>
+
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/bg_ripple_common_mask">
+
+        <Space
+            android:id="@+id/space1"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:10"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <ImageView
+            android:id="@+id/item_payment_icon"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+            android:src="@{paymentWayIcon}"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/space1"
+            app:layout_constraintWidth_percent="0.0666666666666667"
+            tools:src="@drawable/icon_wechat_payment" />
+
+        <Space
+            android:id="@+id/space2"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:10"
+            app:layout_constraintTop_toBottomOf="@+id/item_payment_icon" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            android:text="@{paymentWayName}"
+            android:textColor="#202020"
+            android:textSize="14sp"
+            app:layout_constraintBottom_toBottomOf="@id/item_payment_icon"
+            app:layout_constraintLeft_toRightOf="@id/item_payment_icon"
+            app:layout_constraintTop_toTopOf="@id/item_payment_icon"
+            tools:text="微信支付" />
+
+        <ImageView
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginEnd="20dp"
+            android:src="@{position == selectedPosition ? @drawable/icon_login_check_box_checked : @drawable/icon_login_check_box_unchecked}"
+            app:layout_constraintBottom_toBottomOf="@+id/item_payment_icon"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/item_payment_icon"
+            app:layout_constraintWidth_percent="0.0555555555555556"
+            tools:src="@drawable/icon_login_check_box_checked" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</layout>

+ 4 - 0
app/src/main/res/values/colors.xml

@@ -13,4 +13,8 @@
     <color name="item_data_checked_color">#F2F2F2</color>
     <color name="color_404040">#404040</color>
 
+    <color name="member_buy_price_text_selected">#6A3420</color>
+    <color name="member_buy_price_text_normal">#404040</color>
+    <color name="member_original_price_text_selected">#B27C4B00</color>
+    <color name="member_original_price_text_normal">#B2A7A7A7</color>
 </resources>

+ 38 - 0
app/src/main/res/values/strings.xml

@@ -137,4 +137,42 @@
     <string name="order_member_validity">会员时效</string>
     <string name="order_copy_link">复制教程链接</string>
     <string name="wechat_version_too_low_toast">请先更新到最新版本微信</string>
+    <string name="member_action_title">服务详情</string>
+    <string name="member_buy">立即恢复</string>
+    <string name="member_func_title">选择服务</string>
+    <string name="member_buy_tag_txt">最多人买</string>
+    <string name="rmb">¥</string>
+    <string name="member_price">¥%s</string>
+    <string name="member_scenes_title">使用场景</string>
+    <string name="member_super_title">超级恢复服务范围</string>
+    <string name="scenes_message_recover">信息恢复</string>
+    <string name="stay_tuned">敬请期待</string>
+    <string name="scenes_friend_recover">好友恢复</string>
+    <string name="scenes_img_recover">图片恢复</string>
+    <string name="scenes_file_recover">文件恢复</string>
+    <string name="scenes_video_recover">视频恢复</string>
+    <string name="scenes_audio_recover">音频恢复</string>
+    <string name="scenes_more">更多权益</string>
+    <string name="member_user_evaluate">用户评价</string>
+    <string name="member_service_description">服务说明</string>
+    <string name="retention_give_up_title">确定放弃恢复数据吗?</string>
+    <string name="retention_give_up_text">如果旧数据被覆盖,数据将永久丢失</string>
+    <string name="retention_continue_text">立即恢复</string>
+    <string name="no_pay_way">暂无支付方式</string>
+    <string name="pay_way">支付方式</string>
+    <string name="member_pay_right_now">立即恢复</string>
+    <string name="member_payment_failed">开通失败,请稍后重试</string>
+    <string name="alipay_qr_code_tips">请使用支付宝扫码支付</string>
+    <string name="wechat_pay_qr_code_tips">请使用微信扫码支付</string>
+    <string name="wx_recover_title">订单详情</string>
+    <string name="wx_recover_pay_success">支付成功</string>
+    <string name="wx_recover_order_detail">订单详情</string>
+    <string name="wx_recover_order_no">订单号</string>
+    <string name="wx_recover_copy">复制</string>
+    <string name="wx_recover_auth_code">授权码</string>
+    <string name="wx_recover_tutorial">使用教程</string>
+    <string name="wx_recover_tutorial_content">1.准备一台电脑,一根数据线,一部需要修复数据的手机。\n2.点击\"复制教程链接\"按钮,复制教程链接到电脑浏览器上。\n3.按教程把手机微信文件上传到电脑。\n4.输入以下订单号和验证码登录PC端数据修复工具,按照教程完成微信数据修复。</string>
+    <string name="wx_recover_copy_link">复制教程链接</string>
+    <string name="copy_success">复制成功</string>
+    <string name="no_login">账号未登录</string>
 </resources>

+ 12 - 0
app/src/main/res/values/themes.xml

@@ -21,4 +21,16 @@
         <item name="android:windowTranslucentStatus">true</item>
         <item name="android:statusBarColor">@android:color/transparent</item>
     </style>
+
+    <style name="Theme.Common.BottomSheetDialog" parent="Theme.MaterialComponents.Light.BottomSheetDialog">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
+        <item name="colorOnPrimary">@color/white</item>
+
+        <!-- Customize your theme here. -->
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:backgroundDimAmount">0.7</item>
+    </style>
 </resources>