Selaa lähdekoodia

增加配置获取以及随机文案

zk 1 vuosi sitten
vanhempi
commit
a995d36bc7
31 muutettua tiedostoa jossa 394 lisäystä ja 326 poistoa
  1. 10 5
      app/src/main/java/com/atmob/voiceai/data/api/AtmobApi.java
  2. 7 0
      app/src/main/java/com/atmob/voiceai/data/api/bean/MemberInfoBean.java
  3. 16 0
      app/src/main/java/com/atmob/voiceai/data/api/request/ConfigRequest.java
  4. 35 0
      app/src/main/java/com/atmob/voiceai/data/api/response/ConfigsResponse.java
  5. 14 0
      app/src/main/java/com/atmob/voiceai/data/api/response/RandomTextResponse.java
  6. 0 43
      app/src/main/java/com/atmob/voiceai/data/api/response/VoiceInfoResponse.java
  7. 98 0
      app/src/main/java/com/atmob/voiceai/data/repositories/ConfigRepository.java
  8. 8 7
      app/src/main/java/com/atmob/voiceai/data/repositories/MemberRepository.java
  9. 5 46
      app/src/main/java/com/atmob/voiceai/data/repositories/VoiceAIRepository.java
  10. 4 9
      app/src/main/java/com/atmob/voiceai/module/clonevoice/CloneVoiceViewModel.java
  11. 3 4
      app/src/main/java/com/atmob/voiceai/module/history/HistoryViewModel.java
  12. 2 1
      app/src/main/java/com/atmob/voiceai/module/main/MainViewModel.java
  13. 1 6
      app/src/main/java/com/atmob/voiceai/module/setting/SettingViewModel.java
  14. 0 4
      app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIFragment.java
  15. 49 64
      app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIViewModel.java
  16. 0 1
      app/src/main/java/com/atmob/voiceai/sdk/kochava/KochavaHelper.java
  17. 7 0
      app/src/main/java/com/atmob/voiceai/widget/IgnoreNoEnterActionEditText.java
  18. BIN
      app/src/main/res/drawable-xxhdpi/icon_ad_film.webp
  19. BIN
      app/src/main/res/drawable-xxhdpi/icon_random_txt.webp
  20. BIN
      app/src/main/res/drawable-xxhdpi/icon_total_integration.webp
  21. BIN
      app/src/main/res/drawable-xxhdpi/icon_vip.webp
  22. BIN
      app/src/main/res/drawable-xxhdpi/icon_voice_ai_free_arrow.webp
  23. BIN
      app/src/main/res/drawable-xxhdpi/icon_voice_ai_random_txt.webp
  24. 6 0
      app/src/main/res/drawable/bg_voice_ai_random_txt.xml
  25. 12 0
      app/src/main/res/drawable/progress_random_txt_loading.xml
  26. 1 1
      app/src/main/res/layout/activity_subscription_page.xml
  27. 9 12
      app/src/main/res/layout/fragment_clone_voice.xml
  28. 9 14
      app/src/main/res/layout/fragment_history.xml
  29. 97 102
      app/src/main/res/layout/fragment_voice_ai.xml
  30. 0 6
      app/src/main/res/layout/setting_activity.xml
  31. 1 1
      app/src/main/res/values/strings.xml

+ 10 - 5
app/src/main/java/com/atmob/voiceai/data/api/AtmobApi.java

@@ -4,23 +4,24 @@ package com.atmob.voiceai.data.api;
 import com.atmob.app.lib.base.BaseResponse;
 import com.atmob.voiceai.data.api.request.BaseRequest;
 import com.atmob.voiceai.data.api.request.CloneDeleteRequest;
+import com.atmob.voiceai.data.api.request.ConfigRequest;
 import com.atmob.voiceai.data.api.request.OrderPayRequest;
 import com.atmob.voiceai.data.api.request.OrderStatusRequest;
 import com.atmob.voiceai.data.api.request.PayGoodsRequest;
 import com.atmob.voiceai.data.api.request.SubResumeRequest;
 import com.atmob.voiceai.data.api.request.TextTosSpeechRequest;
-import com.atmob.voiceai.data.api.request.VoiceCloneRequest;
 import com.atmob.voiceai.data.api.request.VoiceHistoryRequest;
 import com.atmob.voiceai.data.api.request.VoiceListRequest;
+import com.atmob.voiceai.data.api.response.ConfigsResponse;
 import com.atmob.voiceai.data.api.response.OrderPayResponse;
 import com.atmob.voiceai.data.api.response.OrderStatusResponse;
 import com.atmob.voiceai.data.api.response.PayGoodsResponse;
+import com.atmob.voiceai.data.api.response.RandomTextResponse;
 import com.atmob.voiceai.data.api.response.TextToSpeechResponse;
 import com.atmob.voiceai.data.api.response.UserInfoResponse;
 import com.atmob.voiceai.data.api.response.VoiceCloneListResponse;
 import com.atmob.voiceai.data.api.response.VoiceCloneResponse;
 import com.atmob.voiceai.data.api.response.VoiceHistoryResponse;
-import com.atmob.voiceai.data.api.response.VoiceInfoResponse;
 import com.atmob.voiceai.data.api.response.VoiceListResponse;
 import com.atmob.voiceai.data.api.response.VoiceTypeResponse;
 import com.atmob.voiceai.data.api.timeout.ConnectionTime;
@@ -33,9 +34,6 @@ import atmob.retrofit2.http.POST;
 public interface AtmobApi {
 
 
-    @POST("/project/voice/v1/voice/info")
-    Single<BaseResponse<VoiceInfoResponse>> getVoiceInfo(@Body BaseRequest request);
-
     @POST("/project/voice/v1/voice/type")
     Single<BaseResponse<VoiceTypeResponse>> getVoiceType(@Body BaseRequest request);
 
@@ -76,4 +74,11 @@ public interface AtmobApi {
     @ConnectionTime(writeTimeout = 120)
     @POST("/project/voice/v1/voice/clone")
     Single<BaseResponse<VoiceCloneResponse>> voiceClone(@Body RequestBody requestBody);
+
+    @POST("/project/voice/v1/confs")
+    Single<BaseResponse<ConfigsResponse>> configs(@Body ConfigRequest request);
+
+    @POST("/project/voice/v1/voice/randomText")
+    Single<BaseResponse<RandomTextResponse>> randomText(@Body BaseRequest request);
+
 }

+ 7 - 0
app/src/main/java/com/atmob/voiceai/data/api/bean/MemberInfoBean.java

@@ -11,6 +11,13 @@ public class MemberInfoBean {
     @SerializedName("timestamp")
     private long timestamp;
 
+    @SerializedName("credit")
+    private int credit;
+
+    public int getCredit() {
+        return credit;
+    }
+
     public long getTimestamp() {
         return timestamp;
     }

+ 16 - 0
app/src/main/java/com/atmob/voiceai/data/api/request/ConfigRequest.java

@@ -0,0 +1,16 @@
+package com.atmob.voiceai.data.api.request;
+
+import com.google.gson.annotations.SerializedName;
+
+public class ConfigRequest extends BaseRequest {
+
+    @SerializedName("confCodes")
+    private String[] confCodes;
+
+
+    public ConfigRequest(String[] confCodes) {
+        this.confCodes = confCodes;
+    }
+
+
+}

+ 35 - 0
app/src/main/java/com/atmob/voiceai/data/api/response/ConfigsResponse.java

@@ -0,0 +1,35 @@
+package com.atmob.voiceai.data.api.response;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+public class ConfigsResponse {
+
+
+    @SerializedName("list")
+    private List<ListBean> list;
+
+    public List<ListBean> getList() {
+        return list;
+    }
+
+
+    public static class ListBean {
+        @SerializedName("confCode")
+        private String confCode;
+        @SerializedName("value")
+        private JSONObject cfg;
+
+
+        public String getConfCode() {
+            return confCode;
+        }
+
+        public JSONObject getCfg() {
+            return cfg;
+        }
+
+    }
+}

+ 14 - 0
app/src/main/java/com/atmob/voiceai/data/api/response/RandomTextResponse.java

@@ -0,0 +1,14 @@
+package com.atmob.voiceai.data.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+public class RandomTextResponse {
+
+
+    @SerializedName("text")
+    private String text;
+
+    public String getText() {
+        return text;
+    }
+}

+ 0 - 43
app/src/main/java/com/atmob/voiceai/data/api/response/VoiceInfoResponse.java

@@ -1,43 +0,0 @@
-package com.atmob.voiceai.data.api.response;
-
-import com.atmob.voiceai.data.api.bean.CloneVoiceListBean;
-import com.google.gson.annotations.SerializedName;
-
-import java.util.List;
-
-public class VoiceInfoResponse {
-
-
-    @SerializedName("voiceTimes")
-    private int voiceTimes;
-    @SerializedName("cloneVoiceAvatar")
-    private String cloneVoiceAvatar;
-    @SerializedName("cloneVoiceName")
-    private String cloneVoiceName;
-
-    public int getVoiceTimes() {
-        return voiceTimes;
-    }
-
-    public void setVoiceTimes(int voiceTimes) {
-        this.voiceTimes = voiceTimes;
-    }
-
-    public String getCloneVoiceAvatar() {
-        return cloneVoiceAvatar;
-    }
-
-    public void setCloneVoiceAvatar(String cloneVoiceAvatar) {
-        this.cloneVoiceAvatar = cloneVoiceAvatar;
-    }
-
-    public String getCloneVoiceName() {
-        return cloneVoiceName;
-    }
-
-    public void setCloneVoiceName(String cloneVoiceName) {
-        this.cloneVoiceName = cloneVoiceName;
-    }
-
-
-}

+ 98 - 0
app/src/main/java/com/atmob/voiceai/data/repositories/ConfigRepository.java

@@ -0,0 +1,98 @@
+package com.atmob.voiceai.data.repositories;
+
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import com.alibaba.fastjson.JSONObject;
+import com.atmob.app.lib.handler.RxHttpHandler;
+import com.atmob.voiceai.data.api.AtmobApi;
+import com.atmob.voiceai.data.api.request.ConfigRequest;
+import com.atmob.voiceai.data.api.response.ConfigsResponse;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import atmob.reactivex.rxjava3.annotations.NonNull;
+import atmob.reactivex.rxjava3.core.Single;
+import atmob.reactivex.rxjava3.core.SingleObserver;
+import atmob.reactivex.rxjava3.disposables.Disposable;
+import atmob.rxjava.utils.RxJavaUtil;
+
+@Singleton
+public class ConfigRepository {
+
+
+    private final String VOICE_TEXT_LIMIT = "voice_text_limit";
+
+    private final String[] configs = {
+            VOICE_TEXT_LIMIT
+    };
+    private final AtmobApi atmobApi;
+
+    private boolean requesting;
+
+    private final MutableLiveData<Integer> voiceTextLimit = new MutableLiveData<>();
+
+    @Inject
+    public ConfigRepository(AtmobApi atmobApi) {
+        this.atmobApi = atmobApi;
+        refreshConfigs();
+    }
+
+    public LiveData<Integer> getVoiceTextLimit() {
+        return voiceTextLimit;
+    }
+
+    private void refreshConfigs() {
+        if (requesting) {
+            return;
+        }
+        getConfig(configs)
+                .subscribe(new SingleObserver<ConfigsResponse>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        requesting = true;
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull ConfigsResponse configsResponse) {
+                        requesting = false;
+                        List<ConfigsResponse.ListBean> list = configsResponse.getList();
+                        if (list == null) {
+                            return;
+                        }
+                        for (ConfigsResponse.ListBean listBean : list) {
+                            if (listBean == null || listBean.getConfCode() == null || listBean.getCfg() == null) {
+                                continue;
+                            }
+                            if (Objects.equals(VOICE_TEXT_LIMIT, listBean.getConfCode())) {
+                                dealVoiceTextLimit(listBean.getCfg());
+                            }
+                        }
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+                        requesting = false;
+                    }
+                });
+    }
+
+    private void dealVoiceTextLimit(@NonNull JSONObject cfg) {
+        if (cfg.containsKey("textLimit")) {
+            voiceTextLimit.postValue(cfg.getIntValue("textLimit"));
+        }
+    }
+
+    private Single<ConfigsResponse> getConfig(String[] configs) {
+        return atmobApi.configs(new ConfigRequest(configs))
+                .compose(RxHttpHandler.handle(true))
+                .retryWhen(RxJavaUtil.retryWhen(null, 100, 3, TimeUnit.SECONDS))
+                .compose(RxJavaUtil.SingleSchedule.ioOnly());
+    }
+}

+ 8 - 7
app/src/main/java/com/atmob/voiceai/data/repositories/MemberRepository.java

@@ -3,6 +3,7 @@ package com.atmob.voiceai.data.repositories;
 
 import android.os.Handler;
 
+import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 
 import com.android.billingclient.api.BillingClient;
@@ -26,7 +27,6 @@ import com.atmob.voiceai.handlers.EventHandler;
 import com.atmob.voiceai.sdk.billing.GPBillingClient;
 import com.atmob.voiceai.utils.BoxingUtil;
 
-import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
@@ -36,16 +36,14 @@ import atmob.reactivex.rxjava3.annotations.NonNull;
 import atmob.reactivex.rxjava3.core.Observable;
 import atmob.reactivex.rxjava3.core.Single;
 import atmob.reactivex.rxjava3.core.SingleObserver;
-import atmob.reactivex.rxjava3.core.SingleSource;
 import atmob.reactivex.rxjava3.disposables.Disposable;
-import atmob.reactivex.rxjava3.functions.Function;
 import atmob.rxjava.utils.RxJavaUtil;
 
 @Singleton
 public class MemberRepository {
 
-
     private final MutableLiveData<Boolean> isMember = new MutableLiveData<>();
+    private final MutableLiveData<Integer> credit = new MutableLiveData<>();
     private final AtmobApi atmobApi;
     private final GPBillingClient gpBillingClient;
     private boolean requestUserInfoDisabled;
@@ -59,10 +57,14 @@ public class MemberRepository {
     }
 
 
-    public MutableLiveData<Boolean> getIsMember() {
+    public LiveData<Boolean> getIsMember() {
         return isMember;
     }
 
+    public LiveData<Integer> getCredit() {
+        return credit;
+    }
+
     public Single<Object> subscriptionResume() {
         return gpBillingClient.queryPurchase(BillingClient.ProductType.SUBS)
                 .map(list -> {
@@ -181,11 +183,10 @@ public class MemberRepository {
                     MemberInfoBean memberInfo = userInfoResponse.getMemberInfo();
                     if (memberInfo != null) {
                         isMember.setValue(memberInfo.isIsMember());
+                        credit.setValue(memberInfo.getCredit());
                         refreshMemberHandler.removeCallbacksAndMessages(null);
                         if (memberInfo.isIsMember()) {
                             refreshMemberHandler.postDelayed(this::refreshUserData, memberInfo.getExpireTime() - memberInfo.getTimestamp());
-                        } else {
-                            VoiceAIRepository.getVoiceAIRepository().refreshVoiceInfo();
                         }
                     }
                 });

+ 5 - 46
app/src/main/java/com/atmob/voiceai/data/repositories/VoiceAIRepository.java

@@ -6,11 +6,9 @@ import android.app.Application;
 import androidx.annotation.IntDef;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.Observer;
 
 import com.atmob.app.lib.handler.RxHttpHandler;
 import com.atmob.app.lib.livedata.SingleLiveEvent;
-import com.atmob.common.logging.AtmobLog;
 import com.atmob.common.runtime.ContextUtil;
 import com.atmob.voiceai.R;
 import com.atmob.voiceai.data.api.AtmobApi;
@@ -19,15 +17,11 @@ import com.atmob.voiceai.data.api.bean.VoiceListBean;
 import com.atmob.voiceai.data.api.request.BaseRequest;
 import com.atmob.voiceai.data.api.request.TextTosSpeechRequest;
 import com.atmob.voiceai.data.api.request.VoiceListRequest;
+import com.atmob.voiceai.data.api.response.RandomTextResponse;
 import com.atmob.voiceai.data.api.response.TextToSpeechResponse;
-import com.atmob.voiceai.data.api.response.VoiceInfoResponse;
 import com.atmob.voiceai.data.api.response.VoiceListResponse;
 import com.atmob.voiceai.data.api.response.VoiceTypeResponse;
 import com.atmob.voiceai.data.consts.ErrorCode;
-import com.atmob.voiceai.handlers.EventHandler;
-import com.atmob.voiceai.sdk.firebase.FirebaseHelper;
-import com.atmob.voiceai.utils.BoxingUtil;
-import com.atmob.voiceai.utils.DownloadUtils;
 import com.atmob.voiceai.utils.ThreePair;
 import com.atmob.voiceai.utils.VoiceFileUtil;
 
@@ -44,7 +38,6 @@ import atmob.reactivex.rxjava3.core.SingleObserver;
 import atmob.reactivex.rxjava3.core.SingleSource;
 import atmob.reactivex.rxjava3.disposables.Disposable;
 import atmob.reactivex.rxjava3.functions.Function;
-import atmob.reactivex.rxjava3.schedulers.Schedulers;
 import atmob.rxjava.utils.RxJavaUtil;
 import dagger.hilt.EntryPoint;
 import dagger.hilt.InstallIn;
@@ -62,7 +55,6 @@ public class VoiceAIRepository {
     private final SingleLiveEvent<?> cloneExecuteSuccess = new SingleLiveEvent<>();
     private final OkHttpClient okHttpClient;
     private boolean textToSpeechRequest;
-    private final MutableLiveData<Integer> adFreeGenerateNumber = new MutableLiveData<>();
 
     private VoiceListBean requestCloneBean;
     private String textToSpeechTxt;
@@ -72,8 +64,6 @@ public class VoiceAIRepository {
     private final SingleLiveEvent<VoiceListBean> recommendClickBean = new SingleLiveEvent<>();
     private final SingleLiveEvent<Integer> useClonedVoiceEvent = new SingleLiveEvent<>();
 
-    private boolean isRequestFreeGenerate;
-
 
     @IntDef({TextToSpeechState.GENERATING, TextToSpeechState.GENERATED, TextToSpeechState.ERROR})
     public @interface TextToSpeechState {
@@ -106,9 +96,6 @@ public class VoiceAIRepository {
         cloneExecuteSuccess.call();
     }
 
-    public LiveData<Integer> getAdFreeGenerateNumber() {
-        return adFreeGenerateNumber;
-    }
 
     public void setRecommendClickBean(VoiceListBean bean) {
         recommendClickBean.setValue(bean);
@@ -130,34 +117,9 @@ public class VoiceAIRepository {
         return textToSpeechState;
     }
 
-
-    public void refreshVoiceInfo() {
-        if (isRequestFreeGenerate || BoxingUtil.boxing(memberRepository.getIsMember().getValue())) {
-            return;
-        }
-        requestVoiceInfo().subscribe(new SingleObserver<VoiceInfoResponse>() {
-            @Override
-            public void onSubscribe(@NonNull Disposable d) {
-                isRequestFreeGenerate = true;
-            }
-
-            @Override
-            public void onSuccess(@NonNull VoiceInfoResponse voiceInfoResponse) {
-                isRequestFreeGenerate = false;
-                adFreeGenerateNumber.setValue(voiceInfoResponse.getVoiceTimes());
-            }
-
-            @Override
-            public void onError(@NonNull Throwable e) {
-                e.printStackTrace();
-                isRequestFreeGenerate = false;
-            }
-        });
-    }
-
-    private Single<VoiceInfoResponse> requestVoiceInfo() {
-        return atmobApi.getVoiceInfo(new BaseRequest())
-                .compose(RxHttpHandler.handle(true))
+    public Single<RandomTextResponse> requestRandomTxt() {
+        return atmobApi.randomText(new BaseRequest())
+                .compose(RxHttpHandler.handle(false))
                 .compose(RxJavaUtil.SingleSchedule.io2Main());
     }
 
@@ -234,10 +196,7 @@ public class VoiceAIRepository {
         return atmobApi.textToSpeech(new TextTosSpeechRequest(id, voiceType, content))
                 .compose(RxHttpHandler.handle(true))
                 .compose(RxJavaUtil.SingleSchedule.io2Main())
-                .doOnSuccess(data -> {
-                    refreshVoiceInfo();
-                    historyRepository.refreshCloneHistory(1);
-                });
+                .doOnSuccess(data -> historyRepository.refreshCloneHistory(1));
     }
 
 

+ 4 - 9
app/src/main/java/com/atmob/voiceai/module/clonevoice/CloneVoiceViewModel.java

@@ -83,9 +83,9 @@ public class CloneVoiceViewModel extends BaseViewModel {
     private final SingleLiveEvent<?> clickLocalUpload = new SingleLiveEvent<>();
 
     private final MutableLiveData<Uri> uploadVoiceUri = new MutableLiveData<>();
-    private final MemberRepository memberRepository;
     private final CloneRepository cloneRepository;
     private final VoiceAIRepository voiceAIRepository;
+    private final MemberRepository memberRepository;
 
     private boolean isSeekbarChanging;
     private Timer timer;
@@ -139,6 +139,9 @@ public class CloneVoiceViewModel extends BaseViewModel {
         });
     }
 
+    public LiveData<Integer> getCredit() {
+        return memberRepository.getCredit();
+    }
 
     public LiveData<String> getRecordTimeTxt() {
         return recordTimeTxt;
@@ -231,10 +234,6 @@ public class CloneVoiceViewModel extends BaseViewModel {
         return cloneTip;
     }
 
-    public LiveData<Boolean> getIsMember() {
-        return memberRepository.getIsMember();
-    }
-
 
     public void setSeekbarChanging(boolean seekbarChanging) {
         isSeekbarChanging = seekbarChanging;
@@ -362,10 +361,6 @@ public class CloneVoiceViewModel extends BaseViewModel {
         if (value == null) {
             return;
         }
-        if (!BoxingUtil.boxing(memberRepository.getIsMember().getValue())) {
-            SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
-            return;
-        }
         File file = FileUtils.uriToFileApiQ(value, ContextUtil.getContext());
         if (state == CloneState.UPLOAD_CHOICE_RECORDING) {
             requestCloneVoice(RECORD_UPLOAD, file);

+ 3 - 4
app/src/main/java/com/atmob/voiceai/module/history/HistoryViewModel.java

@@ -38,15 +38,14 @@ public class HistoryViewModel extends BaseViewModel {
         return historyRepository.isSmoothScrollToTop();
     }
 
+    public LiveData<Integer> getCredit() {
+        return memberRepository.getCredit();
+    }
 
     public LiveData<List<UserVoiceBean>> getVoiceHistoryList() {
         return historyRepository.getVoiceHistoryList();
     }
 
-    public LiveData<Boolean> isMember() {
-        return memberRepository.getIsMember();
-    }
-
     public void onSettingClick() {
         SettingActivity.start(ActivityUtil.getTopActivity());
     }

+ 2 - 1
app/src/main/java/com/atmob/voiceai/module/main/MainViewModel.java

@@ -1,6 +1,7 @@
 package com.atmob.voiceai.module.main;
 
 import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.voiceai.data.repositories.ConfigRepository;
 import com.atmob.voiceai.data.repositories.MemberRepository;
 
 import javax.inject.Inject;
@@ -13,7 +14,7 @@ public class MainViewModel extends BaseViewModel {
 
 
     @Inject
-    public MainViewModel(MemberRepository memberRepository) {
+    public MainViewModel(MemberRepository memberRepository, ConfigRepository configRepository) {
 
     }
 }

+ 1 - 6
app/src/main/java/com/atmob/voiceai/module/setting/SettingViewModel.java

@@ -35,11 +35,9 @@ public class SettingViewModel extends BaseViewModel {
     private final SingleLiveEvent<?> showScoringEvent = new SingleLiveEvent<>();
     private final MutableLiveData<String> versionName = new MutableLiveData<>();
     private final MutableLiveData<String> proName = new MutableLiveData<>();
-    private final MemberRepository memberRepository;
 
     @Inject
-    public SettingViewModel(MemberRepository memberRepository) {
-        this.memberRepository = memberRepository;
+    public SettingViewModel() {
         Context context = ContextUtil.getContext();
         versionName.setValue(context.getString(R.string.version_name, SystemUtil.getVersionName(context)));
         proName.setValue(context.getString(R.string.setting_app_name_pro, context.getString(R.string.app_name)));
@@ -58,9 +56,6 @@ public class SettingViewModel extends BaseViewModel {
         return proName;
     }
 
-    public LiveData<Boolean> isMember() {
-        return memberRepository.getIsMember();
-    }
 
     public LiveData<String> getVersionName() {
         return versionName;

+ 0 - 4
app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIFragment.java

@@ -67,10 +67,6 @@ public class VoiceAIFragment extends BaseFragment<FragmentVoiceAiBinding> {
         });
         voiceViewModel.getScrollToTabPosition().observe(getViewLifecycleOwner(), index -> binding.voiceTab.selectTab(binding.voiceTab.getTabAt(BoxingUtil.boxing(index))));
         voiceViewModel.getPlayExampleVoice().observe(getViewLifecycleOwner(), this::playExampleVoice);
-        voiceViewModel.getShowGenerateAd().observe(getViewLifecycleOwner(), o -> {
-            //TODO 显示广告
-            voiceViewModel.seeAdGenerate();
-        });
         voiceViewModel.getVoiceDetailList().observe(getViewLifecycleOwner(), list -> voiceAIListAdapter.submit(list.first, () -> {
                     if (list.second != null) {
                         voiceViewModel.scrollToListPosition(list.second.getId());

+ 49 - 64
app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIViewModel.java

@@ -4,7 +4,6 @@ import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Pair;
 
-import androidx.annotation.ColorInt;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.Observer;
@@ -18,9 +17,11 @@ import com.atmob.common.runtime.ContextUtil;
 import com.atmob.voiceai.R;
 import com.atmob.voiceai.data.api.bean.TypeListBean;
 import com.atmob.voiceai.data.api.bean.VoiceListBean;
+import com.atmob.voiceai.data.api.response.RandomTextResponse;
 import com.atmob.voiceai.data.api.response.VoiceListResponse;
 import com.atmob.voiceai.data.api.response.VoiceTypeResponse;
 import com.atmob.voiceai.data.consts.EventId;
+import com.atmob.voiceai.data.repositories.ConfigRepository;
 import com.atmob.voiceai.data.repositories.MemberRepository;
 import com.atmob.voiceai.data.repositories.VoiceAIRepository;
 import com.atmob.voiceai.handlers.EventHandler;
@@ -29,7 +30,6 @@ import com.atmob.voiceai.module.generating.VoiceGeneratingActivity;
 import com.atmob.voiceai.module.setting.SettingActivity;
 import com.atmob.voiceai.module.subscription.SubscriptionPageActivity;
 import com.atmob.voiceai.utils.BoxingUtil;
-import com.atmob.voiceai.utils.SpannableUtil;
 import com.atmob.voiceai.utils.ToastUtil;
 
 import java.util.ArrayList;
@@ -48,12 +48,8 @@ public class VoiceAIViewModel extends BaseViewModel {
 
     private final String LAST_GENERATE_TEXT = "last_generate_text";
 
-    private final LiveData<CharSequence> voiceProbationTxt;
     private final MutableLiveData<String> voicePrintTxt = new MutableLiveData<>();
-    private final LiveData<String> voicePrintLimitTxt;
 
-    @ColorInt
-    private final int freeTxtColor;
     private final VoiceAIRepository voiceAIRepository;
 
 
@@ -61,6 +57,7 @@ public class VoiceAIViewModel extends BaseViewModel {
     private final MutableLiveData<List<TypeListBean>> voiceTypeList = new MutableLiveData<>();
     private final MutableLiveData<Pair<List<VoiceListBean>, VoiceListBean>> voiceDetailList = new MutableLiveData<>();
     private final MemberRepository memberRepository;
+    private final ConfigRepository configRepository;
 
     private VoiceListBean choiceVoiceBean;
 
@@ -68,9 +65,11 @@ public class VoiceAIViewModel extends BaseViewModel {
 
     private final SingleLiveEvent<VoiceListBean> playExampleVoice = new SingleLiveEvent<>();
     private final SingleLiveEvent<Integer> scrollToTabPosition = new SingleLiveEvent<>();
-    private final SingleLiveEvent<?> showGenerateAd = new SingleLiveEvent<>();
     private final SingleLiveEvent<VoiceListBean> notifyBean = new SingleLiveEvent<>();
 
+    private final MutableLiveData<Boolean> isRandoming = new MutableLiveData<>();
+    private boolean requestRandom;
+
     private String currentTypeId;
     private Disposable voiceListDisposable;
 
@@ -79,27 +78,22 @@ public class VoiceAIViewModel extends BaseViewModel {
     Observer<Integer> useCloneObserver;
 
     @Inject
-    public VoiceAIViewModel(MemberRepository memberRepository, VoiceAIRepository voiceAIRepository) {
+    public VoiceAIViewModel(MemberRepository memberRepository, VoiceAIRepository voiceAIRepository, ConfigRepository configRepository) {
         this.memberRepository = memberRepository;
         this.voiceAIRepository = voiceAIRepository;
-        voicePrintLimitTxt = Transformations.map(voicePrintTxt, txt -> {
-            int length = 0;
-            if (!TextUtils.isEmpty(txt)) {
-                length = txt.length();
-            }
-            return length + "/200";
-        });
-        freeTxtColor = ContextUtil.getApplication().getResources().getColor(R.color.voice_free_crux_txt_color);
+        this.configRepository = configRepository;
         voicePrintTxt.setValue(KVUtils.getDefault().getString(LAST_GENERATE_TEXT, ""));
-        voiceProbationTxt = Transformations.map(voiceAIRepository.getAdFreeGenerateNumber(), number -> {
-            if (number == null || BoxingUtil.boxing(memberRepository.getIsMember().getValue())) {
-                return "";
-            }
-            return SpannableUtil.getSpannableStringBuilder(ContextUtil.getContext().getString(R.string.voice_ai_get_free_number, number), String.valueOf(number), freeTxtColor, false);
-        });
         iniVoiceAI();
     }
 
+    public LiveData<Boolean> getIsRandoming() {
+        return isRandoming;
+    }
+
+    public LiveData<Integer> getVoiceTextLimit() {
+        return configRepository.getVoiceTextLimit();
+    }
+
     public LiveData<Boolean> getShowQueryLoading() {
         return showQueryLoading;
     }
@@ -116,9 +110,6 @@ public class VoiceAIViewModel extends BaseViewModel {
         return playExampleVoice;
     }
 
-    public LiveData<?> getShowGenerateAd() {
-        return showGenerateAd;
-    }
 
     public LiveData<Pair<List<VoiceListBean>, VoiceListBean>> getVoiceDetailList() {
         return voiceDetailList;
@@ -132,21 +123,6 @@ public class VoiceAIViewModel extends BaseViewModel {
         return scrollToBean;
     }
 
-    public LiveData<Integer> getAdFreeGenerateNumber() {
-        return voiceAIRepository.getAdFreeGenerateNumber();
-    }
-
-    public LiveData<Boolean> isMember() {
-        return memberRepository.getIsMember();
-    }
-
-    public LiveData<CharSequence> getVoiceProbationTxt() {
-        return voiceProbationTxt;
-    }
-
-    public LiveData<String> getVoicePrintLimitTxt() {
-        return voicePrintLimitTxt;
-    }
 
     public MutableLiveData<String> getVoicePrintTxt() {
         return voicePrintTxt;
@@ -157,6 +133,10 @@ public class VoiceAIViewModel extends BaseViewModel {
     }
 
 
+    public LiveData<Integer> getCredit() {
+        return memberRepository.getCredit();
+    }
+
     public void onGenerateClick() {
         EventHandler.report(EventId.homegenerate_001);
         String content = voicePrintTxt.getValue();
@@ -168,19 +148,7 @@ public class VoiceAIViewModel extends BaseViewModel {
             ToastUtil.show(R.string.voice_ai_no_choice, ToastUtil.LENGTH_SHORT);
             return;
         }
-        if (BoxingUtil.boxing(isMember().getValue())) {
-            requestGenerateVoice();
-            return;
-        }
-        if (choiceVoiceBean.isHasPro()) {
-            SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
-            return;
-        }
-        if (BoxingUtil.boxing(voiceAIRepository.getAdFreeGenerateNumber().getValue()) > 0) {
-            showGenerateAd.call();
-            return;
-        }
-        SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
+        requestGenerateVoice();
     }
 
     private void requestGenerateVoice() {
@@ -372,14 +340,6 @@ public class VoiceAIViewModel extends BaseViewModel {
         setChoiceVoiceBean(voiceListBean, true);
     }
 
-    public void seeAdGenerate() {
-        if (choiceVoiceBean == null) {
-            ToastUtil.show(R.string.voice_ai_no_choice, ToastUtil.LENGTH_SHORT);
-            return;
-        }
-        requestGenerateVoice();
-    }
-
     public void setVoicePlayEnd() {
         if (choiceVoiceBean != null) {
             choiceVoiceBean.setVoicePlayState(VoiceListBean.VoicePlayState.INITIAL);
@@ -396,11 +356,36 @@ public class VoiceAIViewModel extends BaseViewModel {
         SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
     }
 
-    public void onGetMoreClick() {
-        EventHandler.report(EventId.homegetmore_001);
-        SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
+    public void onRandomTxtClick() {
+        if (requestRandom) {
+            return;
+        }
+        voiceAIRepository.requestRandomTxt()
+                .subscribe(new SingleObserver<RandomTextResponse>() {
+                    @Override
+                    public void onSubscribe(@NonNull Disposable d) {
+                        addDisposable(d);
+                        requestRandom = true;
+                        isRandoming.setValue(true);
+                    }
+
+                    @Override
+                    public void onSuccess(@NonNull RandomTextResponse randomTextResponse) {
+                        requestRandom = false;
+                        isRandoming.setValue(false);
+                        voicePrintTxt.setValue(randomTextResponse.getText());
+                    }
+
+                    @Override
+                    public void onError(@NonNull Throwable e) {
+                        ErrorHelper.errorThrowableToast(e, ToastUtil.LENGTH_SHORT);
+                        requestRandom = false;
+                        isRandoming.setValue(false);
+                    }
+                });
     }
 
+
     @Override
     protected void onCleared() {
         super.onCleared();

+ 0 - 1
app/src/main/java/com/atmob/voiceai/sdk/kochava/KochavaHelper.java

@@ -34,7 +34,6 @@ public class KochavaHelper {
 
         firebaseHelper.getMessagingToken(token -> Engagement.getInstance().registerPushToken(token));
         firebaseHelper.addOnMessagingTokenChangeListener(token -> Engagement.getInstance().registerPushToken(token));
-
         // This callback handler will fire on every launch. Optionally check the isRetrieved if you wish to only parse these results once.
         InstallAttributionApi currentInstallAttribution = Tracker.getInstance().getInstallAttribution();
         if (!currentInstallAttribution.isRetrieved()) {

+ 7 - 0
app/src/main/java/com/atmob/voiceai/widget/IgnoreNoEnterActionEditText.java

@@ -1,6 +1,7 @@
 package com.atmob.voiceai.widget;
 
 import android.content.Context;
+import android.text.InputFilter;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.inputmethod.EditorInfo;
@@ -30,6 +31,12 @@ public class IgnoreNoEnterActionEditText extends AppCompatEditText {
         return conn;
     }
 
+    public void setMaxLength(int maxLength) {
+        InputFilter[] filters = new InputFilter[1];
+        filters[0] = new InputFilter.LengthFilter(maxLength);
+        setFilters(filters);
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();

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


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


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


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


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


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


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

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

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

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+            android:drawable="@drawable/icon_random_txt"
+            android:fromDegrees="0"
+            android:pivotX="50.0%"
+            android:pivotY="50.0%"
+            android:toDegrees="720" />
+        <span style="white-space:pre" />
+    </item>
+</layer-list>

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

@@ -289,7 +289,7 @@
                     android:id="@+id/iv_vip"
                     android:layout_width="0dp"
                     android:layout_height="0dp"
-                    android:src="@drawable/icon_vip"
+                    android:src="@drawable/icon_total_integration"
                     app:layout_constraintBottom_toBottomOf="@+id/iv_sub"
                     app:layout_constraintDimensionRatio="1:1"
                     app:layout_constraintHorizontal_chainStyle="packed"

+ 9 - 12
app/src/main/res/layout/fragment_clone_voice.xml

@@ -772,37 +772,39 @@
             android:background="@drawable/bg_voice_ai_vip"
             android:onClick="@{()-> cloneVoiceViewModel.onGoSubscriptionClick()}"
             app:layout_constraintBottom_toBottomOf="@+id/v_menu"
-            app:layout_constraintDimensionRatio="58:28"
+            app:layout_constraintDimensionRatio="80:28"
             app:layout_constraintStart_toStartOf="@+id/v_menu"
             app:layout_constraintTop_toTopOf="@+id/v_menu"
-            app:layout_constraintWidth_percent="0.1611111111111111" />
+            app:layout_constraintWidth_percent="0.2222222222222222" />
 
 
         <ImageView
             android:id="@+id/iv_vip"
             android:layout_width="0dp"
             android:layout_height="0dp"
-            android:src="@drawable/icon_vip"
+            android:src="@drawable/icon_total_integration"
             app:layout_constraintBottom_toBottomOf="@+id/v_vip_bg"
-            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintDimensionRatio="39:42"
             app:layout_constraintHorizontal_chainStyle="packed"
             app:layout_constraintLeft_toLeftOf="@+id/v_vip_bg"
             app:layout_constraintRight_toLeftOf="@+id/tv_vip_title"
             app:layout_constraintTop_toTopOf="@+id/v_vip_bg"
-            app:layout_constraintWidth_percent="0.0444444444444444" />
+            app:layout_constraintWidth_percent="0.0344444444444444" />
+
 
         <TextView
             android:id="@+id/tv_vip_title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="4dp"
-            android:text="@string/voice_pro"
+            android:text="@{String.valueOf(cloneVoiceViewModel.credit)}"
             android:textColor="@color/colorPrimaryVariant"
             android:textSize="14dp"
             app:layout_constraintBottom_toBottomOf="@+id/v_vip_bg"
             app:layout_constraintLeft_toRightOf="@+id/iv_vip"
             app:layout_constraintRight_toRightOf="@+id/v_vip_bg"
-            app:layout_constraintTop_toTopOf="@+id/v_vip_bg" />
+            app:layout_constraintTop_toTopOf="@+id/v_vip_bg"
+            tools:text="200" />
 
         <ImageView
             android:id="@+id/iv_setting"
@@ -817,11 +819,6 @@
             app:layout_constraintTop_toTopOf="@+id/v_menu"
             app:layout_constraintWidth_percent="0.0888888888888889" />
 
-        <androidx.constraintlayout.widget.Group
-            isGone="@{cloneVoiceViewModel.isMember}"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            app:constraint_referenced_ids="v_vip_bg,iv_vip,tv_vip_title" />
 
 
     </androidx.constraintlayout.widget.ConstraintLayout>

+ 9 - 14
app/src/main/res/layout/fragment_history.xml

@@ -48,36 +48,37 @@
             android:background="@drawable/bg_voice_ai_vip"
             android:onClick="@{()-> historyViewModel.onGoSubscriptionClick()}"
             app:layout_constraintBottom_toBottomOf="@+id/v_tool_bar"
-            app:layout_constraintDimensionRatio="58:28"
+            app:layout_constraintDimensionRatio="80:28"
             app:layout_constraintStart_toStartOf="@+id/v_tool_bar"
             app:layout_constraintTop_toTopOf="@+id/v_tool_bar"
-            app:layout_constraintWidth_percent="0.1611111111111111" />
+            app:layout_constraintWidth_percent="0.2222222222222222" />
 
         <ImageView
             android:id="@+id/iv_vip"
             android:layout_width="0dp"
             android:layout_height="0dp"
-            android:src="@drawable/icon_vip"
+            android:src="@drawable/icon_total_integration"
             app:layout_constraintBottom_toBottomOf="@+id/v_vip_bg"
-            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintDimensionRatio="39:42"
             app:layout_constraintHorizontal_chainStyle="packed"
             app:layout_constraintLeft_toLeftOf="@+id/v_vip_bg"
             app:layout_constraintRight_toLeftOf="@+id/tv_vip_title"
             app:layout_constraintTop_toTopOf="@+id/v_vip_bg"
-            app:layout_constraintWidth_percent="0.0444444444444444" />
+            app:layout_constraintWidth_percent="0.0344444444444444" />
 
         <TextView
             android:id="@+id/tv_vip_title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="4dp"
-            android:text="@string/voice_pro"
+            android:text="@{String.valueOf(historyViewModel.credit)}"
             android:textColor="@color/colorPrimaryVariant"
             android:textSize="14dp"
             app:layout_constraintBottom_toBottomOf="@+id/v_vip_bg"
             app:layout_constraintLeft_toRightOf="@+id/iv_vip"
             app:layout_constraintRight_toRightOf="@+id/v_vip_bg"
-            app:layout_constraintTop_toTopOf="@+id/v_vip_bg" />
+            app:layout_constraintTop_toTopOf="@+id/v_vip_bg"
+            tools:text="200" />
 
         <TextView
             android:layout_width="wrap_content"
@@ -103,18 +104,12 @@
             app:layout_constraintTop_toTopOf="@+id/v_tool_bar"
             app:layout_constraintWidth_percent="0.0666666666666667" />
 
-        <androidx.constraintlayout.widget.Group
-            isGone="@{historyViewModel.isMember}"
-            app:constraint_referenced_ids="v_vip_bg,iv_vip,tv_vip_title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-
 
         <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
             android:id="@+id/swipe_history_layout"
-            android:paddingTop="10dp"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:paddingTop="10dp"
             app:layout_constrainedHeight="true"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintTop_toBottomOf="@id/v_tool_bar">

+ 97 - 102
app/src/main/res/layout/fragment_voice_ai.xml

@@ -54,36 +54,37 @@
                 android:background="@drawable/bg_voice_ai_vip"
                 android:onClick="@{()-> voiceAIViewModel.onGoSubscriptionClick()}"
                 app:layout_constraintBottom_toBottomOf="@+id/v_tool_bar"
-                app:layout_constraintDimensionRatio="58:28"
+                app:layout_constraintDimensionRatio="80:28"
                 app:layout_constraintStart_toStartOf="@+id/v_tool_bar"
                 app:layout_constraintTop_toTopOf="@+id/v_tool_bar"
-                app:layout_constraintWidth_percent="0.1611111111111111" />
+                app:layout_constraintWidth_percent="0.2222222222222222" />
 
             <ImageView
                 android:id="@+id/iv_vip"
                 android:layout_width="0dp"
                 android:layout_height="0dp"
-                android:src="@drawable/icon_vip"
+                android:src="@drawable/icon_total_integration"
                 app:layout_constraintBottom_toBottomOf="@+id/v_vip_bg"
-                app:layout_constraintDimensionRatio="1:1"
+                app:layout_constraintDimensionRatio="39:42"
                 app:layout_constraintHorizontal_chainStyle="packed"
                 app:layout_constraintLeft_toLeftOf="@+id/v_vip_bg"
                 app:layout_constraintRight_toLeftOf="@+id/tv_vip_title"
                 app:layout_constraintTop_toTopOf="@+id/v_vip_bg"
-                app:layout_constraintWidth_percent="0.0444444444444444" />
+                app:layout_constraintWidth_percent="0.0344444444444444" />
 
             <TextView
                 android:id="@+id/tv_vip_title"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginStart="4dp"
-                android:text="@string/voice_pro"
+                android:text="@{String.valueOf(voiceAIViewModel.credit)}"
                 android:textColor="@color/colorPrimaryVariant"
                 android:textSize="14dp"
                 app:layout_constraintBottom_toBottomOf="@+id/v_vip_bg"
                 app:layout_constraintLeft_toRightOf="@+id/iv_vip"
                 app:layout_constraintRight_toRightOf="@+id/v_vip_bg"
-                app:layout_constraintTop_toTopOf="@+id/v_vip_bg" />
+                app:layout_constraintTop_toTopOf="@+id/v_vip_bg"
+                tools:text="200" />
 
             <TextView
                 android:layout_width="wrap_content"
@@ -122,75 +123,17 @@
                     app:layout_constraintDimensionRatio="360:12"
                     app:layout_constraintTop_toTopOf="parent" />
 
-                <View
-                    android:id="@+id/v_free_get_bg"
-                    android:layout_width="match_parent"
-                    android:layout_height="0dp"
-                    android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
-                    android:alpha="0.1"
-                    android:background="@drawable/bg_voice_ai_free"
-                    android:onClick="@{()-> voiceAIViewModel.onGetMoreClick()}"
-                    app:layout_constraintDimensionRatio="336:36"
-                    app:layout_constraintTop_toBottomOf="@+id/space1" />
-
-
-                <TextView
-                    android:id="@+id/tv_generate_free_desc"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="14dp"
-                    android:text="@{voiceAIViewModel.voiceProbationTxt}"
-                    android:textColor="@color/white"
-                    android:textSize="14sp"
-                    app:layout_constraintBottom_toBottomOf="@+id/v_free_get_bg"
-                    app:layout_constraintStart_toStartOf="@+id/v_free_get_bg"
-                    app:layout_constraintTop_toTopOf="@+id/v_free_get_bg"
-                    tools:text="You have 3 chances today." />
-
-                <ImageView
-                    android:id="@+id/iv_get_free_arrow"
-                    android:layout_width="0dp"
-                    android:layout_height="0dp"
-                    android:layout_marginEnd="8dp"
-                    android:src="@drawable/icon_voice_ai_free_arrow"
-                    app:layout_constraintBottom_toBottomOf="@+id/v_free_get_bg"
-                    app:layout_constraintDimensionRatio="61:60"
-                    app:layout_constraintEnd_toEndOf="@+id/v_free_get_bg"
-                    app:layout_constraintTop_toTopOf="@+id/v_free_get_bg"
-                    app:layout_constraintWidth_percent="0.0555555555555556" />
-
-                <TextView
-                    android:id="@+id/tv_get_free_txt"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/voice_ai_get_free"
-                    android:textColor="@color/white"
-                    android:textSize="14sp"
-                    app:layout_constraintBottom_toBottomOf="@+id/iv_get_free_arrow"
-                    app:layout_constraintEnd_toStartOf="@+id/iv_get_free_arrow"
-                    app:layout_constraintTop_toTopOf="@+id/iv_get_free_arrow" />
-
-                <Space
-                    android:id="@+id/sapce2"
-                    android:layout_width="match_parent"
-                    android:layout_height="0dp"
-                    app:layout_constraintDimensionRatio="360:8"
-                    app:layout_constraintTop_toBottomOf="@+id/v_free_get_bg" />
-
-
                 <TextView
                     android:id="@+id/tv_your_txt_title"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
-                    android:layout_marginTop="12dp"
                     android:text="@string/voice_your_text"
                     android:textColor="@color/white"
                     android:textSize="16sp"
                     android:textStyle="bold"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/sapce2" />
-
+                    app:layout_constraintTop_toBottomOf="@+id/space1" />
 
                 <View
                     android:id="@+id/v_voice_print_bg"
@@ -204,6 +147,7 @@
 
                 <com.atmob.voiceai.widget.IgnoreNoEnterActionEditText
                     android:id="@+id/et_voice_print"
+                    maxLength="@{voiceAIViewModel.voiceTextLimit }"
                     android:layout_width="0dp"
                     android:layout_height="0dp"
                     android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
@@ -212,7 +156,6 @@
                     android:background="@null"
                     android:gravity="start"
                     android:hint="@string/voice_ai_print_hint"
-                    android:maxLength="200"
                     android:text="@={voiceAIViewModel.voicePrintTxt}"
                     android:textColor="@color/white"
                     android:textColorHint="@color/white50"
@@ -222,30 +165,109 @@
                     app:layout_constraintStart_toStartOf="@+id/v_voice_print_bg"
                     app:layout_constraintTop_toTopOf="@+id/v_voice_print_bg" />
 
+
+                <View
+                    android:onClick="@{()-> voiceAIViewModel.onRandomTxtClick()}"
+                    android:id="@+id/v_voice_ai_random_txt"
+                    android:layout_width="0dp"
+                    android:layout_height="0dp"
+                    android:layout_marginStart="6dp"
+                    android:background="@drawable/bg_voice_ai_random_txt"
+                    app:layout_constraintBottom_toBottomOf="@+id/tv_print_clear"
+                    app:layout_constraintDimensionRatio="104:28"
+                    app:layout_constraintStart_toStartOf="@+id/v_voice_print_bg"
+                    app:layout_constraintTop_toTopOf="@+id/tv_print_clear"
+                    app:layout_constraintWidth_percent="0.2888888888888889" />
+
+                <Space
+                    android:id="@+id/space_voice_ai_random_txt"
+                    android:layout_width="0dp"
+                    android:layout_height="0dp"
+                    app:layout_constraintBottom_toBottomOf="@+id/v_voice_ai_random_txt"
+                    app:layout_constraintDimensionRatio="1:1"
+                    app:layout_constraintHorizontal_chainStyle="packed"
+                    app:layout_constraintLeft_toLeftOf="@+id/v_voice_ai_random_txt"
+                    app:layout_constraintRight_toLeftOf="@+id/tv_voice_ai_random_txt"
+                    app:layout_constraintTop_toTopOf="@+id/v_voice_ai_random_txt"
+                    app:layout_constraintWidth_percent="0.0333333333333333" />
+
+                <ImageView
+                    isGone="@{voiceAIViewModel.isRandoming}"
+                    android:layout_width="0dp"
+                    android:layout_height="0dp"
+                    android:src="@drawable/icon_voice_ai_random_txt"
+                    app:layout_constraintBottom_toBottomOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintDimensionRatio="1:1"
+                    app:layout_constraintEnd_toEndOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintStart_toStartOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintTop_toTopOf="@+id/space_voice_ai_random_txt" />
+
+                <ProgressBar
+                    android:id="@+id/progress_random_txt"
+                    isGone="@{!voiceAIViewModel.isRandoming}"
+                    android:layout_width="0dp"
+                    android:layout_height="0dp"
+                    android:indeterminate="true"
+                    android:indeterminateDrawable="@drawable/progress_random_txt_loading"
+                    app:layout_constraintBottom_toBottomOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintDimensionRatio="1:1"
+                    app:layout_constraintEnd_toEndOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintStart_toStartOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintTop_toTopOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintVertical_chainStyle="packed" />
+
+
+                <TextView
+                    android:id="@+id/tv_voice_ai_random_txt"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="4dp"
+                    android:text="@string/voice_ai_random_txt"
+                    android:textColor="@color/white"
+                    android:textSize="12sp"
+                    app:layout_constraintBottom_toBottomOf="@+id/v_voice_ai_random_txt"
+                    app:layout_constraintLeft_toRightOf="@+id/space_voice_ai_random_txt"
+                    app:layout_constraintRight_toRightOf="@+id/v_voice_ai_random_txt"
+                    app:layout_constraintTop_toTopOf="@+id/v_voice_ai_random_txt" />
+
                 <TextView
                     android:id="@+id/tv_print_clear"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginStart="9dp"
-                    android:layout_marginBottom="@dimen/app_common_page_horizontal_padding"
+                    android:layout_marginEnd="20dp"
                     android:onClick="@{()-> voiceAIViewModel.clearPrintTxt()}"
                     android:text="@string/voice_ai_clear_txt"
                     android:textColor="@color/colorPrimaryVariant"
                     android:textSize="14sp"
-                    app:layout_constraintBottom_toBottomOf="@+id/v_voice_print_bg"
-                    app:layout_constraintStart_toStartOf="@+id/v_voice_print_bg" />
+                    app:layout_constraintBottom_toBottomOf="@+id/tv_print_length"
+                    app:layout_constraintEnd_toStartOf="@+id/tv_print_length"
+                    app:layout_constraintTop_toTopOf="@+id/tv_print_length" />
+
+
+                <TextView
+                    android:id="@+id/tv_print_length"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@{String.valueOf(voiceAIViewModel.voicePrintTxt.length)}"
+                    android:textColor="@color/white50"
+                    android:textSize="14sp"
+                    app:layout_constraintBottom_toBottomOf="@+id/tv_print_limit"
+                    app:layout_constraintRight_toLeftOf="@+id/tv_print_limit"
+                    app:layout_constraintTop_toTopOf="@+id/tv_print_limit"
+                    tools:text="0" />
 
                 <TextView
+                    android:id="@+id/tv_print_limit"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginEnd="@dimen/app_common_page_horizontal_padding"
-                    android:text="@{voiceAIViewModel.voicePrintLimitTxt}"
+                    android:layout_marginBottom="@dimen/app_common_page_horizontal_padding"
+                    android:text='@{ "/" + voiceAIViewModel.voiceTextLimit}'
                     android:textColor="@color/white50"
                     android:textSize="14sp"
-                    app:layout_constraintBottom_toBottomOf="@+id/tv_print_clear"
+                    app:layout_constraintBottom_toBottomOf="@+id/v_voice_print_bg"
                     app:layout_constraintEnd_toEndOf="@+id/v_voice_print_bg"
-                    app:layout_constraintTop_toTopOf="@+id/tv_print_clear"
-                    tools:text="0/200" />
+                    tools:text="/500" />
 
 
                 <TextView
@@ -286,22 +308,9 @@
                     app:tabPaddingStart="0dp"
                     app:tabRippleColor="#00000000" />
 
-
-                <androidx.constraintlayout.widget.Group
-                    isGone="@{voiceAIViewModel.isMember || voiceAIViewModel.voiceProbationTxt == null || voiceAIViewModel.voiceProbationTxt.toString().length() == 0 }"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    app:constraint_referenced_ids="v_free_get_bg,tv_generate_free_desc,sapce2,iv_get_free_arrow,tv_get_free_txt" />
-
             </androidx.constraintlayout.widget.ConstraintLayout>
 
 
-            <androidx.constraintlayout.widget.Group
-                isGone="@{voiceAIViewModel.isMember}"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:constraint_referenced_ids="v_vip_bg,iv_vip,tv_vip_title" />
-
         </androidx.constraintlayout.widget.ConstraintLayout>
 
         <RelativeLayout
@@ -361,19 +370,6 @@
                     app:layout_constraintDimensionRatio="336:48"
                     app:layout_constraintTop_toTopOf="@+id/v_generate" />
 
-                <ImageView
-                    android:id="@+id/iv_ad"
-                    isGone="@{voiceAIViewModel.isMember()}"
-                    android:layout_width="0dp"
-                    android:layout_height="0dp"
-                    android:src="@drawable/icon_ad_film"
-                    app:layout_constraintBottom_toBottomOf="@+id/v_generate_btn"
-                    app:layout_constraintDimensionRatio="1:1"
-                    app:layout_constraintHorizontal_chainStyle="packed"
-                    app:layout_constraintLeft_toLeftOf="@+id/v_generate_btn"
-                    app:layout_constraintRight_toLeftOf="@+id/tv_generate_txt"
-                    app:layout_constraintTop_toTopOf="@+id/v_generate_btn"
-                    app:layout_constraintWidth_percent="0.0388888888888889" />
 
                 <TextView
                     android:id="@+id/tv_generate_txt"
@@ -385,7 +381,6 @@
                     android:textSize="17sp"
                     android:textStyle="bold"
                     app:layout_constraintBottom_toBottomOf="@+id/v_generate_btn"
-                    app:layout_constraintLeft_toRightOf="@+id/iv_ad"
                     app:layout_constraintRight_toRightOf="@+id/v_generate_btn"
                     app:layout_constraintTop_toTopOf="@+id/v_generate_btn" />
             </androidx.constraintlayout.widget.ConstraintLayout>

+ 0 - 6
app/src/main/res/layout/setting_activity.xml

@@ -106,12 +106,6 @@
             app:layout_constraintDimensionRatio="360:22"
             app:layout_constraintTop_toBottomOf="@+id/view_setting_pro" />
 
-        <androidx.constraintlayout.widget.Group
-            isGone="@{settingViewModel.isMember}"
-            app:constraint_referenced_ids="view_setting_pro,tv_setting_pro,iv_setting_pro_arrow"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"

+ 1 - 1
app/src/main/res/values/strings.xml

@@ -12,7 +12,6 @@
     <string name="voice_ai_print_hint">Please enter the text to be generated…</string>
     <string name="voice_all">AI Voice</string>
     <string name="voice_ai_generate">Generate</string>
-    <string name="voice_ai_get_free">Get more</string>
     <string name="voice_ai_get_free_number">You have %d chances today.</string>
     <string name="net_error_message">network timeout</string>
     <string name="add_voice">Add Voice</string>
@@ -122,4 +121,5 @@
     <string name="scoring_content">We are working hard for better user experience.Please take a minute to rate us.</string>
     <string name="scoring_advice_hint">Enter your advice</string>
     <string name="thanks_feedback">Submit success</string>
+    <string name="voice_ai_random_txt">Random text</string>
 </resources>