Browse Source

增加选中效果

zk 1 year ago
parent
commit
edcd9ee4d6

+ 3 - 0
app/src/main/AndroidManifest.xml

@@ -39,6 +39,9 @@
             android:name=".module.main.MainActivity"
             android:launchMode="singleTask"
             android:screenOrientation="portrait" />
+        <activity
+            android:name=".module.subscription.SubscriptionPageActivity"
+            android:screenOrientation="portrait" />
     </application>
 
 

+ 0 - 3
app/src/main/java/com/atmob/voiceai/data/api/AtmobApi.java

@@ -32,9 +32,6 @@ public interface AtmobApi {
     @POST("/project/voice/v1/voice/list")
     Single<BaseResponse<VoiceListResponse>> getVoiceList(@Body VoiceListRequest request);
 
-    @POST("/project/voice/v1/voice/textToSpeech")
-    Single<BaseResponse<TextToSpeechResponse>> textToSpeech(@Body TextTosSpeechRequest request);
-
     @POST("/project/voice/v1/clone/list")
     Single<BaseResponse<VoiceCloneListResponse>> getCloneList(@Body BaseRequest request);
 

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

@@ -0,0 +1,16 @@
+package com.atmob.voiceai.data.api;
+
+import com.atmob.app.lib.base.BaseResponse;
+import com.atmob.voiceai.data.api.request.TextTosSpeechRequest;
+import com.atmob.voiceai.data.api.response.TextToSpeechResponse;
+
+import atmob.reactivex.rxjava3.core.Single;
+import atmob.retrofit2.http.Body;
+import atmob.retrofit2.http.POST;
+
+public interface GenerateApi {
+
+
+    @POST("/project/voice/v1/voice/textToSpeech")
+    Single<BaseResponse<TextToSpeechResponse>> textToSpeech(@Body TextTosSpeechRequest request);
+}

+ 42 - 1
app/src/main/java/com/atmob/voiceai/data/api/bean/VoiceListBean.java

@@ -1,8 +1,12 @@
 package com.atmob.voiceai.data.api.bean;
 
+import androidx.databinding.BaseObservable;
+import androidx.databinding.Bindable;
+
+import com.atmob.voiceai.BR;
 import com.google.gson.annotations.SerializedName;
 
-public class VoiceListBean {
+public class VoiceListBean extends BaseObservable {
     @SerializedName("id")
     private int id;
     @SerializedName("typeId")
@@ -22,6 +26,39 @@ public class VoiceListBean {
 
     private int viewType;
 
+    private boolean check;
+
+    @VoicePlayState
+    private int voicePlayState;
+
+    public @interface VoicePlayState {
+
+        int INITIAL = 0;
+        int LOADING = 1;
+        int PLAYING = 2;
+    }
+
+    @Bindable
+    @VoicePlayState
+    public int getVoicePlayState() {
+        return voicePlayState;
+    }
+
+    public void setVoicePlayState(@VoicePlayState int voicePlayState) {
+        this.voicePlayState = voicePlayState;
+        notifyPropertyChanged(BR.voicePlayState);
+    }
+
+    @Bindable
+    public boolean isCheck() {
+        return check;
+    }
+
+    public void setCheck(boolean check) {
+        this.check = check;
+        notifyPropertyChanged(BR.check);
+    }
+
     public int getViewType() {
         return viewType;
     }
@@ -54,20 +91,24 @@ public class VoiceListBean {
         this.typeId = typeId;
     }
 
+    @Bindable
     public String getName() {
         return name;
     }
 
     public void setName(String name) {
         this.name = name;
+        notifyPropertyChanged(BR.name);
     }
 
+    @Bindable
     public String getAvatarUrl() {
         return avatarUrl;
     }
 
     public void setAvatarUrl(String avatarUrl) {
         this.avatarUrl = avatarUrl;
+        notifyPropertyChanged(BR.avatarUrl);
     }
 
     public String getVoiceUrl() {

+ 2 - 0
app/src/main/java/com/atmob/voiceai/data/repositories/VoiceAIRepository.java

@@ -51,4 +51,6 @@ public class VoiceAIRepository {
                 .compose(RxHttpHandler.handle(true))
                 .compose(RxJavaUtil.SingleSchedule.io2Main());
     }
+
+
 }

+ 20 - 0
app/src/main/java/com/atmob/voiceai/di/NetworkModule.java

@@ -3,9 +3,12 @@ package com.atmob.voiceai.di;
 import com.atmob.network.okhttp.AtmobOkHttpClient;
 import com.atmob.voiceai.BuildConfig;
 import com.atmob.voiceai.data.api.AtmobApi;
+import com.atmob.voiceai.data.api.GenerateApi;
 import com.atmob.voiceai.data.consts.Constants;
 import com.google.gson.Gson;
 
+import java.util.concurrent.TimeUnit;
+
 import javax.inject.Singleton;
 
 import atmob.okhttp3.OkHttpClient;
@@ -35,4 +38,21 @@ public class NetworkModule {
                 .create(AtmobApi.class);
     }
 
+    @Singleton
+    @Provides
+    public static GenerateApi provideGenerateApi(Gson gson) {
+        OkHttpClient okHttpClient = AtmobOkHttpClient.newInstance(ATMOB_TAG, BuildConfig.DEBUG).newBuilder()
+                .connectTimeout(30, TimeUnit.SECONDS)
+                .readTimeout(15, TimeUnit.SECONDS)
+                .writeTimeout(15, TimeUnit.SECONDS)
+                .build();
+        return new Retrofit.Builder()
+                .client(okHttpClient)
+                .addConverterFactory(GsonConverterFactory.create(gson))
+                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
+                .baseUrl(Constants.Atmob_Server_Base_URL)
+                .build()
+                .create(GenerateApi.class);
+    }
+
 }

+ 23 - 1
app/src/main/java/com/atmob/voiceai/module/main/MainActivity.java

@@ -24,7 +24,7 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
 
 
     private MainViewModel mainViewModel;
-
+    private static final String TO_TAB_FRAGMENT = "to_tab_fragment";
     private TabLayoutMediator tabLayoutMediator;
     private MainPagerAdapter mainPagerAdapter;
 
@@ -36,6 +36,28 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
         context.startActivity(intent);
     }
 
+    public static void start(Context context, Class<? extends Fragment> cls) {
+        Intent intent = new Intent(context, MainActivity.class);
+        if (!(context instanceof android.app.Activity)) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        if (cls != null) {
+            intent.putExtra(TO_TAB_FRAGMENT, cls);
+        }
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        if (intent != null) {
+            Class<? extends Fragment> cls = (Class<? extends Fragment>) intent.getSerializableExtra(TO_TAB_FRAGMENT);
+            if (cls != null) {
+                binding.mainTabLayout.selectTab(binding.mainTabLayout.getTabAt(mainPagerAdapter.getPosition(cls)));
+            }
+        }
+    }
+
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);

+ 29 - 0
app/src/main/java/com/atmob/voiceai/module/subscription/SubscriptionPageActivity.java

@@ -0,0 +1,29 @@
+package com.atmob.voiceai.module.subscription;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import com.atmob.app.lib.base.BaseActivity;
+import com.atmob.voiceai.databinding.ActivitySubscriptionPageBinding;
+
+import dagger.hilt.android.AndroidEntryPoint;
+
+@AndroidEntryPoint
+public class SubscriptionPageActivity extends BaseActivity<ActivitySubscriptionPageBinding> {
+
+
+    public static void start(Context context) {
+        Intent intent = new Intent(context, SubscriptionPageActivity.class);
+        if (!(context instanceof Activity)) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        context.startActivity(intent);
+    }
+
+
+    @Override
+    protected boolean shouldImmersion() {
+        return true;
+    }
+}

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

@@ -13,8 +13,11 @@ import androidx.recyclerview.widget.RecyclerView;
 import com.atmob.app.lib.base.BaseFragment;
 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.databinding.FragmentVoiceAiBinding;
 import com.atmob.voiceai.databinding.ItemVoiceAiTabBinding;
+import com.atmob.voiceai.module.clonevoice.CloneVoiceFragment;
+import com.atmob.voiceai.module.main.MainActivity;
 import com.atmob.voiceai.utils.GridLayoutItemDecoration;
 import com.google.android.material.tabs.TabLayout;
 import com.gyf.immersionbar.ImmersionBar;
@@ -39,6 +42,11 @@ public class VoiceAIFragment extends BaseFragment<FragmentVoiceAiBinding> {
     }
 
     private void initObserver() {
+        voiceViewModel.getShowGenerateAd().observe(getViewLifecycleOwner(), o -> {
+            //TODO 显示广告
+
+            voiceViewModel.seeAdGenerate();
+        });
         voiceViewModel.getVoiceDetailList().observe(getViewLifecycleOwner(), list -> voiceAIListAdapter.submit(list)
         );
         voiceViewModel.getVoiceTypeList().observe(getViewLifecycleOwner(), list -> {
@@ -72,6 +80,17 @@ public class VoiceAIFragment extends BaseFragment<FragmentVoiceAiBinding> {
 
     private void initVoiceList() {
         voiceAIListAdapter = new VoiceAIListAdapter(getViewLifecycleOwner());
+        voiceAIListAdapter.setActionHandler(new VoiceAIListAdapter.ActionHandler() {
+            @Override
+            public void addClick() {
+                MainActivity.start(requireActivity(), CloneVoiceFragment.class);
+            }
+
+            @Override
+            public void choiceItemClick(VoiceListBean voiceListBean) {
+                voiceViewModel.setChoiceVoiceBean(voiceListBean);
+            }
+        });
         binding.ryVoiceView.setAdapter(voiceAIListAdapter);
         GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 4);
         binding.ryVoiceView.setLayoutManager(gridLayoutManager);

+ 27 - 0
app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIListAdapter.java

@@ -26,6 +26,14 @@ public class VoiceAIListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
 
     public static final int TYPE_FOOT = 3;
 
+    private ActionHandler actionHandler;
+
+    private VoiceListBean checkBean;
+
+    public void setActionHandler(ActionHandler actionHandler) {
+        this.actionHandler = actionHandler;
+    }
+
     public VoiceAIListAdapter(@NonNull LifecycleOwner lifecycleOwner) {
         this.lifecycleOwner = lifecycleOwner;
         this.listDiffer = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<VoiceListBean>() {
@@ -121,6 +129,18 @@ public class VoiceAIListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
             super(binding.getRoot());
             this.binding = binding;
             binding.setLifecycleOwner(lifecycleOwner);
+            binding.setAddClick(v -> {
+                if (actionHandler != null) actionHandler.addClick();
+            });
+            binding.setChoiceClick(v -> {
+                VoiceListBean viewBean = binding.getBean();
+                if (checkBean != null) {
+                    checkBean.setCheck(false);
+                }
+                viewBean.setCheck(true);
+                checkBean = viewBean;
+                if (actionHandler != null) actionHandler.choiceItemClick(viewBean);
+            });
         }
 
 
@@ -129,4 +149,11 @@ public class VoiceAIListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
         }
     }
 
+
+    public interface ActionHandler {
+        void addClick();
+
+        void choiceItemClick(VoiceListBean voiceListBean);
+    }
+
 }

+ 71 - 19
app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIViewModel.java

@@ -8,7 +8,9 @@ import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.Transformations;
 
 import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.app.lib.livedata.SingleLiveEvent;
 import com.atmob.common.data.KVUtils;
+import com.atmob.common.runtime.ActivityUtil;
 import com.atmob.common.runtime.ContextUtil;
 import com.atmob.voiceai.R;
 import com.atmob.voiceai.data.api.bean.CloneVoiceListBean;
@@ -20,6 +22,7 @@ import com.atmob.voiceai.data.api.response.VoiceTypeResponse;
 import com.atmob.voiceai.data.repositories.MemberRepository;
 import com.atmob.voiceai.data.repositories.VoiceAIRepository;
 import com.atmob.voiceai.helper.ErrorHelper;
+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;
@@ -48,11 +51,16 @@ public class VoiceAIViewModel extends BaseViewModel {
     private final int freeTxtColor;
     private final VoiceAIRepository voiceAIRepository;
 
-    private final MutableLiveData<List<CloneVoiceListBean>> userCloneList = new MutableLiveData<>();
+    private CloneVoiceListBean cloneBean;
+    private VoiceListBean addVoiceBean;
 
     private final MutableLiveData<List<TypeListBean>> voiceTypeList = new MutableLiveData<>();
     private final MutableLiveData<List<VoiceListBean>> voiceDetailList = new MutableLiveData<>();
 
+    private final MutableLiveData<VoiceListBean> choiceVoiceBean = new MutableLiveData<>();
+
+    private final SingleLiveEvent<?> showGenerateAd = new SingleLiveEvent<>();
+
     private int currentTypeId = -1;
     private Disposable voiceListDisposable;
 
@@ -80,6 +88,10 @@ public class VoiceAIViewModel extends BaseViewModel {
         iniVoiceAI();
     }
 
+    public LiveData<?> getShowGenerateAd() {
+        return showGenerateAd;
+    }
+
     public LiveData<List<VoiceListBean>> getVoiceDetailList() {
         return voiceDetailList;
     }
@@ -114,6 +126,27 @@ public class VoiceAIViewModel extends BaseViewModel {
     }
 
     public void onGenerateClick() {
+        VoiceListBean bean = choiceVoiceBean.getValue();
+        if (bean == null) {
+            ToastUtil.show(R.string.voice_ai_no_choice, ToastUtil.LENGTH_SHORT);
+            return;
+        }
+        if (BoxingUtil.boxing(isMember().getValue())) {
+            requestGenerateVoice(bean);
+            return;
+        }
+        if (bean.isHasPro()) {
+            SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
+            return;
+        }
+        if (BoxingUtil.boxing(adFreeGenerateNumber.getValue()) > 0) {
+            showGenerateAd.call();
+            return;
+        }
+        SubscriptionPageActivity.start(ActivityUtil.getTopActivity());
+    }
+
+    private void requestGenerateVoice(VoiceListBean bean) {
 
     }
 
@@ -135,12 +168,16 @@ public class VoiceAIViewModel extends BaseViewModel {
                 adFreeGenerateNumber.setValue(voiceInfoResponse.getVoiceTimes());
                 List<CloneVoiceListBean> cloneVoiceList = voiceInfoResponse.getCloneVoiceList();
                 if (cloneVoiceList != null && !cloneVoiceList.isEmpty()) {
-                    for (CloneVoiceListBean cloneVoiceListBean : cloneVoiceList) {
-                        cloneVoiceListBean.setCloneVoiceAvatar(voiceInfoResponse.getCloneVoiceAvatar());
-                        cloneVoiceListBean.setCloneVoiceName(voiceInfoResponse.getCloneVoiceName());
+                    cloneBean = cloneVoiceList.get(0);
+                    cloneBean.setCloneVoiceAvatar(voiceInfoResponse.getCloneVoiceAvatar());
+                    cloneBean.setCloneVoiceName(voiceInfoResponse.getCloneVoiceName());
+                    if (addVoiceBean != null) {
+                        addVoiceBean.setId(cloneBean.getId());
+                        addVoiceBean.setName(cloneBean.getCloneVoiceName());
+                        addVoiceBean.setAvatarUrl(cloneBean.getCloneVoiceAvatar());
+                        addVoiceBean.setVoiceUrl(cloneBean.getVoiceUrl());
                     }
                 }
-                userCloneList.setValue(cloneVoiceList);
             }
 
             @Override
@@ -195,18 +232,23 @@ public class VoiceAIViewModel extends BaseViewModel {
                 if (voiceList == null) {
                     voiceList = new ArrayList<>();
                 }
-                List<CloneVoiceListBean> value = userCloneList.getValue();
-                if (value == null || value.isEmpty()) {
+                if (cloneBean == null) {
                     VoiceListBean cloneVoiceListBean = new VoiceListBean();
                     cloneVoiceListBean.setAddIcon(true);
                     cloneVoiceListBean.setId(-1);
                     cloneVoiceListBean.setName(ContextUtil.getContext().getString(R.string.add_voice));
+                    addVoiceBean = cloneVoiceListBean;
                     voiceList.add(0, cloneVoiceListBean);
                 } else {
-                    List<VoiceListBean> list = getVoiceListBeans(value);
-                    voiceList.addAll(0, list);
+                    VoiceListBean cloneVoiceBean = getVoiceBeans(cloneBean);
+                    voiceList.add(0, cloneVoiceBean);
                 }
                 voiceDetailList.setValue(voiceList);
+                VoiceListBean choiceBean = choiceVoiceBean.getValue();
+                if (choiceBean != null) {
+                    choiceBean.setCheck(false);
+                }
+                choiceVoiceBean.setValue(null);
             }
 
             @Override
@@ -216,16 +258,26 @@ public class VoiceAIViewModel extends BaseViewModel {
         });
     }
 
-    @androidx.annotation.NonNull
-    private List<VoiceListBean> getVoiceListBeans(List<CloneVoiceListBean> value) {
-        List<VoiceListBean> list = new ArrayList<>();
-        for (CloneVoiceListBean cloneVoiceListBean : value) {
-            VoiceListBean voiceListBean = new VoiceListBean();
-            voiceListBean.setName(cloneVoiceListBean.getCloneVoiceName());
-            voiceListBean.setAvatarUrl(cloneVoiceListBean.getCloneVoiceAvatar());
-            voiceListBean.setId(cloneVoiceListBean.getId());
-            list.add(voiceListBean);
+    @NonNull
+    private VoiceListBean getVoiceBeans(@NonNull CloneVoiceListBean bean) {
+        VoiceListBean voiceListBean = new VoiceListBean();
+        voiceListBean.setName(bean.getCloneVoiceName());
+        voiceListBean.setAvatarUrl(bean.getCloneVoiceAvatar());
+        voiceListBean.setId(bean.getId());
+        return voiceListBean;
+    }
+
+    public void setChoiceVoiceBean(VoiceListBean voiceListBean) {
+        choiceVoiceBean.setValue(voiceListBean);
+
+    }
+
+    public void seeAdGenerate() {
+        VoiceListBean bean = choiceVoiceBean.getValue();
+        if (bean == null) {
+            ToastUtil.show(R.string.voice_ai_no_choice, ToastUtil.LENGTH_SHORT);
+            return;
         }
-        return list;
+        requestGenerateVoice(bean);
     }
 }

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

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <stroke
+        android:width="2dp"
+        android:color="@color/colorPrimaryVariant" />
+    <corners android:radius="12dp" />
+</shape>

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

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 21 - 0
app/src/main/res/layout/item_voice_ai_list.xml

@@ -8,6 +8,14 @@
         <variable
             name="bean"
             type="com.atmob.voiceai.data.api.bean.VoiceListBean" />
+
+        <variable
+            name="choiceClick"
+            type="android.view.View.OnClickListener" />
+
+        <variable
+            name="addClick"
+            type="android.view.View.OnClickListener" />
     </data>
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -26,20 +34,33 @@
             isGone="@{!bean.isAddIcon}"
             android:layout_width="match_parent"
             android:layout_height="0dp"
+            android:onClick="@{addClick}"
             android:src="@drawable/icon_voice_ai_add"
             app:layout_constraintDimensionRatio="1:1"
             app:layout_constraintTop_toTopOf="parent" />
 
         <ImageView
+            android:id="@+id/iv_avatar"
             imageUrl="@{bean.avatarUrl}"
             isGone="@{bean.isAddIcon}"
             radius="@{12}"
             android:layout_width="match_parent"
             android:layout_height="0dp"
+            android:onClick="@{choiceClick}"
             android:src="@drawable/icon_voice_ai_add"
             app:layout_constraintDimensionRatio="1:1"
             app:layout_constraintTop_toTopOf="parent" />
 
+        <View
+            android:background="@drawable/bg_voice_ai_list_check"
+            isGone="@{!bean.check}"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            app:layout_constraintBottom_toBottomOf="@+id/iv_avatar"
+            app:layout_constraintEnd_toEndOf="@+id/iv_avatar"
+            app:layout_constraintStart_toStartOf="@+id/iv_avatar"
+            app:layout_constraintTop_toTopOf="@+id/iv_avatar" />
+
         <TextView
             isGone="@{!bean.hasNew}"
             android:layout_width="0dp"

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

@@ -15,4 +15,5 @@
     <string name="net_error_message">network timeout</string>
     <string name="add_voice">Add Voice</string>
     <string name="voice_new">New</string>
+    <string name="voice_ai_no_choice">Please choose</string>
 </resources>