Browse Source

完成主界面搭建

zk 1 year ago
parent
commit
c39b055a8f
34 changed files with 814 additions and 32 deletions
  1. 29 0
      app/src/main/java/com/atmob/voiceai/data/repositories/MemberRepository.java
  2. 12 1
      app/src/main/java/com/atmob/voiceai/module/clonevoice/CloneVoiceFragment.java
  3. 12 1
      app/src/main/java/com/atmob/voiceai/module/history/HistoryFragment.java
  4. 1 1
      app/src/main/java/com/atmob/voiceai/module/main/MainActivity.java
  5. 2 2
      app/src/main/java/com/atmob/voiceai/module/main/MainPagerAdapter.java
  6. 50 0
      app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIFragment.java
  7. 77 0
      app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIViewModel.java
  8. 0 10
      app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAiFragment.java
  9. 122 0
      app/src/main/java/com/atmob/voiceai/utils/SpannableUtil.java
  10. 61 0
      app/src/main/java/com/atmob/voiceai/widget/IgnoreNoEnterActionEditText.java
  11. BIN
      app/src/main/res/drawable-xxhdpi/bg_voice_ai_header_top_bg.webp
  12. BIN
      app/src/main/res/drawable-xxhdpi/icon_ad_film.webp
  13. BIN
      app/src/main/res/drawable-xxhdpi/icon_tab_clone_voice_checked.webp
  14. BIN
      app/src/main/res/drawable-xxhdpi/icon_tab_clone_voice_un_check.webp
  15. BIN
      app/src/main/res/drawable-xxhdpi/icon_tab_history_checked.webp
  16. BIN
      app/src/main/res/drawable-xxhdpi/icon_tab_history_un_check.webp
  17. BIN
      app/src/main/res/drawable-xxhdpi/icon_vip.webp
  18. BIN
      app/src/main/res/drawable-xxhdpi/icon_voice_ai_free_arrow.webp
  19. BIN
      app/src/main/res/drawable-xxhdpi/icon_voice_ai_menu.webp
  20. 5 0
      app/src/main/res/drawable/bg_voice_ai.xml
  21. 21 0
      app/src/main/res/drawable/bg_voice_ai_btn.xml
  22. 5 0
      app/src/main/res/drawable/bg_voice_ai_free.xml
  23. 24 0
      app/src/main/res/drawable/bg_voice_ai_vip.xml
  24. 7 0
      app/src/main/res/drawable/bg_voice_generate.xml
  25. 2 2
      app/src/main/res/drawable/selector_icon_main_tab_clone_voice.xml
  26. 2 2
      app/src/main/res/drawable/selector_icon_main_tab_hirstory.xml
  27. 11 3
      app/src/main/res/layout/activity_main.xml
  28. 6 0
      app/src/main/res/layout/fragment_clone_voice.xml
  29. 6 0
      app/src/main/res/layout/fragment_history.xml
  30. 341 0
      app/src/main/res/layout/fragment_voice_ai.xml
  31. 3 9
      app/src/main/res/values/colors.xml
  32. 5 0
      app/src/main/res/values/dimens.xml
  33. 9 0
      app/src/main/res/values/strings.xml
  34. 1 1
      app/src/main/res/values/themes.xml

+ 29 - 0
app/src/main/java/com/atmob/voiceai/data/repositories/MemberRepository.java

@@ -0,0 +1,29 @@
+package com.atmob.voiceai.data.repositories;
+
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
+public class MemberRepository {
+
+
+    private final MutableLiveData<Boolean> isMember = new MutableLiveData<>();
+    private final MutableLiveData<Integer> adFreeGenerateNumber = new MutableLiveData<>(3);
+
+    @Inject
+    public MemberRepository() {
+
+    }
+
+    public LiveData<Boolean> getIsMember() {
+        return isMember;
+    }
+
+    public LiveData<Integer> getAdFreeGenerateNumber() {
+        return adFreeGenerateNumber;
+    }
+}

+ 12 - 1
app/src/main/java/com/atmob/voiceai/module/clonevoice/CloneVoiceFragment.java

@@ -1,9 +1,20 @@
 package com.atmob.voiceai.module.clonevoice;
 
+import androidx.annotation.NonNull;
+
 import com.atmob.app.lib.base.BaseFragment;
+import com.atmob.voiceai.databinding.FragmentCloneVoiceBinding;
+import com.gyf.immersionbar.ImmersionBar;
 
 import dagger.hilt.android.AndroidEntryPoint;
 
 @AndroidEntryPoint
-public class CloneVoiceFragment extends BaseFragment {
+public class CloneVoiceFragment extends BaseFragment<FragmentCloneVoiceBinding> {
+
+
+    @Override
+    protected void configImmersion(@NonNull ImmersionBar immersionBar) {
+        super.configImmersion(immersionBar);
+        immersionBar.statusBarDarkFont(false);
+    }
 }

+ 12 - 1
app/src/main/java/com/atmob/voiceai/module/history/HistoryFragment.java

@@ -1,10 +1,21 @@
 package com.atmob.voiceai.module.history;
 
+import androidx.annotation.NonNull;
+
 import com.atmob.app.lib.base.BaseFragment;
+import com.atmob.voiceai.databinding.FragmentHistoryBinding;
+import com.gyf.immersionbar.ImmersionBar;
 
 import dagger.hilt.android.AndroidEntryPoint;
 import dagger.hilt.android.HiltAndroidApp;
 
 @AndroidEntryPoint
-public class HistoryFragment extends BaseFragment {
+public class HistoryFragment extends BaseFragment<FragmentHistoryBinding> {
+
+
+    @Override
+    protected void configImmersion(@NonNull ImmersionBar immersionBar) {
+        super.configImmersion(immersionBar);
+        immersionBar.statusBarDarkFont(false);
+    }
 }

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

@@ -106,7 +106,7 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
     @Override
     protected void configImmersion(@NonNull ImmersionBar immersionBar) {
         super.configImmersion(immersionBar);
-        immersionBar.statusBarDarkFont(true);
+        immersionBar.statusBarDarkFont(false);
     }
 
     @Override

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

@@ -9,7 +9,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
 import com.atmob.voiceai.R;
 import com.atmob.voiceai.module.clonevoice.CloneVoiceFragment;
 import com.atmob.voiceai.module.history.HistoryFragment;
-import com.atmob.voiceai.module.voiceai.VoiceAiFragment;
+import com.atmob.voiceai.module.voiceai.VoiceAIFragment;
 
 import java.util.Arrays;
 import java.util.List;
@@ -17,7 +17,7 @@ import java.util.List;
 public class MainPagerAdapter extends FragmentStateAdapter {
 
     private final List<MainPagerItem> mainPagerItems = Arrays.asList(
-            new MainPagerItem(R.string.main_pager_voice_ai, R.drawable.selector_icon_main_tab_voice, VoiceAiFragment.class),
+            new MainPagerItem(R.string.main_pager_voice_ai, R.drawable.selector_icon_main_tab_voice, VoiceAIFragment.class),
             new MainPagerItem(R.string.main_pager_clone_voice, R.drawable.selector_icon_main_tab_clone_voice, CloneVoiceFragment.class),
             new MainPagerItem(R.string.main_pager_history, R.drawable.selector_icon_main_tab_hirstory, HistoryFragment.class)
     );

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

@@ -0,0 +1,50 @@
+package com.atmob.voiceai.module.voiceai;
+
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.atmob.app.lib.base.BaseFragment;
+import com.atmob.voiceai.databinding.FragmentVoiceAiBinding;
+import com.gyf.immersionbar.ImmersionBar;
+
+import dagger.hilt.android.AndroidEntryPoint;
+
+
+@AndroidEntryPoint
+public class VoiceAIFragment extends BaseFragment<FragmentVoiceAiBinding> {
+
+
+    private VoiceAIViewModel voiceViewModel;
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        initView();
+        initObserver();
+    }
+
+
+    private void initView() {
+
+    }
+
+    private void initObserver() {
+
+    }
+
+    @Override
+    protected void initViewModel() {
+        super.initViewModel();
+        voiceViewModel = getViewModelProvider().get(VoiceAIViewModel.class);
+        binding.setVoiceAIViewModel(voiceViewModel);
+    }
+
+    @Override
+    protected void configImmersion(@NonNull ImmersionBar immersionBar) {
+        super.configImmersion(immersionBar);
+        immersionBar.statusBarDarkFont(false);
+    }
+}

+ 77 - 0
app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAIViewModel.java

@@ -0,0 +1,77 @@
+package com.atmob.voiceai.module.voiceai;
+
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+
+import androidx.annotation.ColorInt;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
+
+import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.common.runtime.ContextUtil;
+import com.atmob.voiceai.R;
+import com.atmob.voiceai.data.repositories.MemberRepository;
+import com.atmob.voiceai.utils.BoxingUtil;
+import com.atmob.voiceai.utils.SpannableUtil;
+
+import javax.inject.Inject;
+
+import dagger.hilt.android.lifecycle.HiltViewModel;
+
+@HiltViewModel
+public class VoiceAIViewModel extends BaseViewModel {
+
+
+    private final LiveData<CharSequence> voiceProbationTxt;
+    private final MutableLiveData<String> voicePrintTxt = new MutableLiveData<>();
+    private final LiveData<String> voicePrintLimitTxt;
+    private final MemberRepository memberRepository;
+
+    @ColorInt
+    private final int freeTxtColor;
+
+    @Inject
+    public VoiceAIViewModel(MemberRepository memberRepository) {
+        this.memberRepository = memberRepository;
+        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);
+        voiceProbationTxt = Transformations.map(memberRepository.getAdFreeGenerateNumber(), number -> {
+            if (BoxingUtil.boxing(number) <= 0) {
+                return null;
+            }
+            String allTxt = ContextUtil.getContext().getString(R.string.voice_ai_get_free_number, number);
+            return SpannableUtil.getSpannableStringBuilder(allTxt, String.valueOf(number), freeTxtColor, false);
+        });
+    }
+
+    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;
+    }
+
+    public void clearPrintTxt() {
+        voicePrintTxt.setValue("");
+    }
+
+    public void onGenerateClick() {
+
+    }
+}

+ 0 - 10
app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAiFragment.java

@@ -1,10 +0,0 @@
-package com.atmob.voiceai.module.voiceai;
-
-import com.atmob.app.lib.base.BaseFragment;
-
-import dagger.hilt.android.AndroidEntryPoint;
-
-
-@AndroidEntryPoint
-public class VoiceAiFragment extends BaseFragment {
-}

+ 122 - 0
app/src/main/java/com/atmob/voiceai/utils/SpannableUtil.java

@@ -0,0 +1,122 @@
+package com.atmob.voiceai.utils;
+
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+public class SpannableUtil {
+
+    public static SpannableStringBuilder getSpannableStringBuilder(SpannableStringBuilder spannableStringBuilder, String targetTxt, int color, boolean isLine) {
+        if (spannableStringBuilder == null) {
+            return null;
+        }
+        int targetTextStart = spannableStringBuilder.toString().indexOf(targetTxt);
+        ClickableSpan targetSpan = new ClickableSpan() {
+
+            @Override
+            public void onClick(@NonNull View widget) {
+
+            }
+
+            @Override
+            public void updateDrawState(@NonNull TextPaint ds) {
+                ds.setColor(color);
+                ds.setUnderlineText(isLine);
+            }
+        };
+        spannableStringBuilder.setSpan(targetSpan, targetTextStart,
+                targetTextStart + targetTxt.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        return spannableStringBuilder;
+    }
+
+    public static SpannableStringBuilder getSpannableStringBuilder(String allTxt, String targetTxt, int color, boolean isLine) {
+        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(allTxt);
+        int targetTextStart = allTxt.indexOf(targetTxt);
+        ClickableSpan targetSpan = new ClickableSpan() {
+
+            @Override
+            public void onClick(@NonNull View widget) {
+
+            }
+
+            @Override
+            public void updateDrawState(@NonNull TextPaint ds) {
+                ds.setColor(color);
+                ds.setUnderlineText(isLine);
+            }
+        };
+        spannableStringBuilder.setSpan(targetSpan, targetTextStart,
+                targetTextStart + targetTxt.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        return spannableStringBuilder;
+    }
+
+
+    public static SpannableStringBuilder getSpannableStringBuilder(String allTxt, String[] targetTxt, int color, boolean isLine) {
+        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(allTxt);
+        int[] targetTextStart = new int[targetTxt.length];
+        for (int i = 0; i < targetTxt.length; i++) {
+            targetTextStart[i] = allTxt.indexOf(targetTxt[i]);
+        }
+        for (int i = 0; i < targetTxt.length; i++) {
+            ClickableSpan targetSpan = new ClickableSpan() {
+                @Override
+                public void onClick(@NonNull View widget) {
+
+                }
+
+                @Override
+                public void updateDrawState(@NonNull TextPaint ds) {
+                    ds.setColor(color);
+                    ds.setUnderlineText(isLine);
+                }
+            };
+            if (targetTextStart[i] < 0) {
+                continue;
+            }
+            spannableStringBuilder.setSpan(targetSpan, targetTextStart[i],
+                    targetTextStart[i] + targetTxt[i].length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        }
+        return spannableStringBuilder;
+    }
+
+
+    public static void getAgreementSpannableStringBuilder(TextView targetView, String allTxt, String[] targetTxt, int color, boolean isLine, View.OnClickListener... clickListener) {
+        if (clickListener.length > 0)
+            targetView.setMovementMethod(LinkMovementMethod.getInstance());
+        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(allTxt);
+        int[] targetTextStart = new int[targetTxt.length];
+        for (int i = 0; i < targetTxt.length; i++) {
+            targetTextStart[i] = allTxt.indexOf(targetTxt[i]);
+        }
+
+        for (int i = 0; i < targetTxt.length; i++) {
+            int finalI = i;
+            ClickableSpan targetSpan = new ClickableSpan() {
+                @Override
+                public void onClick(@NonNull View widget) {
+                    if (finalI < clickListener.length && clickListener[finalI] != null) {
+                        clickListener[finalI].onClick(widget);
+                    }
+                }
+
+                @Override
+                public void updateDrawState(@NonNull TextPaint ds) {
+                    ds.setColor(color);
+                    ds.setUnderlineText(isLine);
+                }
+            };
+            if (targetTextStart[i] < 0) {
+                continue;
+            }
+            spannableStringBuilder.setSpan(targetSpan, targetTextStart[i],
+                    targetTextStart[i] + targetTxt[i].length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        }
+        targetView.setText(spannableStringBuilder);
+    }
+}

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

@@ -0,0 +1,61 @@
+package com.atmob.voiceai.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.AppCompatEditText;
+
+public class IgnoreNoEnterActionEditText extends AppCompatEditText {
+    public IgnoreNoEnterActionEditText(@NonNull Context context) {
+        super(context);
+    }
+
+    public IgnoreNoEnterActionEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public IgnoreNoEnterActionEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(@NonNull EditorInfo outAttrs) {
+        InputConnection conn = super.onCreateInputConnection(outAttrs);
+        outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+        return conn;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final int action = event.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN) {
+            getParent().requestDisallowInterceptTouchEvent(true);
+        } else if (action == MotionEvent.ACTION_MOVE) {
+            getParent().requestDisallowInterceptTouchEvent(canVerticalScroll());
+        } else if (action == MotionEvent.ACTION_UP) {
+            getParent().requestDisallowInterceptTouchEvent(false);
+        }
+        return super.onTouchEvent(event);
+    }
+
+    private boolean canVerticalScroll() {
+        //滚动的距离
+        int scrollY = getScrollY();
+        //控件内容的总高度
+        int scrollRange = getLayout().getHeight();
+        //控件实际显示的高度
+        int scrollExtent = getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
+        //控件内容总高度与实际显示高度的差值
+        int scrollDifference = scrollRange - scrollExtent;
+
+        if (scrollDifference == 0) {
+            return false;
+        }
+        return (scrollY > 0) || (scrollY < scrollDifference - 1);
+    }
+}

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


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


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


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


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


BIN
app/src/main/res/drawable-xxhdpi/icon_tab_history_un_check.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_menu.webp


+ 5 - 0
app/src/main/res/drawable/bg_voice_ai.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="12dp" />
+    <solid android:color="#32333C" />
+</shape>

+ 21 - 0
app/src/main/res/drawable/bg_voice_ai_btn.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <gradient
+                android:endColor="#14C8C8"
+                android:startColor="#06D6A0" />
+            <corners android:radius="100dp" />
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/black50">
+            <item android:id="@android:id/mask">
+                <shape android:shape="rectangle">
+                    <solid android:color="@color/black50" />
+                    <corners android:radius="100dp" />
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>

+ 5 - 0
app/src/main/res/drawable/bg_voice_ai_free.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="100dp" />
+    <solid android:color="@color/colorPrimaryVariant" />
+</shape>

+ 24 - 0
app/src/main/res/drawable/bg_voice_ai_vip.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <gradient
+                android:endColor="#0594D7"
+                android:startColor="#12F45D" />
+            <padding
+                android:bottom="1dp"
+                android:left="1dp"
+                android:right="1dp"
+                android:top="1dp" />
+            <corners android:radius="100dp" />
+        </shape>
+    </item>
+
+    <item>
+        <shape>
+            <solid android:color="#203F38" />
+            <corners android:radius="100dp" />
+
+        </shape>
+    </item>
+</layer-list>

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

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:startColor="#202123"
+        android:endColor="@color/transparent"
+        android:angle="90" />
+</shape>

+ 2 - 2
app/src/main/res/drawable/selector_icon_main_tab_clone_voice.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/icon_tab_voice_checked" android:state_selected="true" />
-    <item android:drawable="@drawable/icon_tab_voice_un_check" />
+    <item android:drawable="@drawable/icon_tab_clone_voice_checked" android:state_selected="true" />
+    <item android:drawable="@drawable/icon_tab_clone_voice_un_check" />
 </selector>

+ 2 - 2
app/src/main/res/drawable/selector_icon_main_tab_hirstory.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/icon_tab_voice_checked" android:state_selected="true" />
-    <item android:drawable="@drawable/icon_tab_voice_un_check" />
+    <item android:drawable="@drawable/icon_tab_history_checked" android:state_selected="true" />
+    <item android:drawable="@drawable/icon_tab_history_un_check" />
 </selector>

+ 11 - 3
app/src/main/res/layout/activity_main.xml

@@ -2,20 +2,28 @@
 <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="match_parent">
+    android:layout_height="match_parent"
+    android:background="@color/colorPrimary">
 
     <androidx.viewpager2.widget.ViewPager2
         android:id="@+id/main_view_pager"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        app:layout_constraintBottom_toTopOf="@id/main_tab_layout"
+        app:layout_constraintBottom_toTopOf="@id/v_tab_divider"
         app:layout_constraintTop_toTopOf="parent" />
 
+    <View
+        android:id="@+id/v_tab_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="#32333C"
+        app:layout_constraintBottom_toTopOf="@+id/main_tab_layout" />
+
     <com.google.android.material.tabs.TabLayout
         android:id="@+id/main_tab_layout"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:translationZ="10dp"
+        android:background="@color/colorPrimary"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintDimensionRatio="360:56"
         app:tabIconTint="@android:color/transparent"

+ 6 - 0
app/src/main/res/layout/fragment_clone_voice.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>

+ 6 - 0
app/src/main/res/layout/fragment_history.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>

+ 341 - 0
app/src/main/res/layout/fragment_voice_ai.xml

@@ -0,0 +1,341 @@
+<?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="voiceAIViewModel"
+            type="com.atmob.voiceai.module.voiceai.VoiceAIViewModel" />
+
+        <import type="com.atmob.common.ui.SizeUtil" />
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/colorPrimary">
+
+        <ImageView
+            android:id="@+id/iv_header_bg"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:src="@drawable/bg_voice_ai_header_top_bg"
+            app:layout_constraintDimensionRatio="836:556"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintWidth_percent="0.5083333333333333" />
+
+
+        <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" />
+
+        <View
+            android:id="@+id/v_tool_bar"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintDimensionRatio="360:44"
+            app:layout_constraintTop_toBottomOf="@+id/space_status_bar" />
+
+        <View
+            android:id="@+id/v_vip_bg"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+            android:background="@drawable/bg_voice_ai_vip"
+            app:layout_constraintBottom_toBottomOf="@+id/v_tool_bar"
+            app:layout_constraintDimensionRatio="58:28"
+            app:layout_constraintStart_toStartOf="@+id/v_tool_bar"
+            app:layout_constraintTop_toTopOf="@+id/v_tool_bar"
+            app:layout_constraintWidth_percent="0.1611111111111111" />
+
+        <ImageView
+            android:id="@+id/iv_vip"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:src="@drawable/icon_vip"
+            app:layout_constraintBottom_toBottomOf="@+id/v_vip_bg"
+            app:layout_constraintDimensionRatio="1:1"
+            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" />
+
+        <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: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" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/voice_ai"
+            android:textColor="@color/white"
+            android:textSize="18sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@+id/v_tool_bar"
+            app:layout_constraintEnd_toEndOf="@+id/v_tool_bar"
+            app:layout_constraintStart_toStartOf="@+id/v_tool_bar"
+            app:layout_constraintTop_toTopOf="@+id/v_tool_bar" />
+
+        <ImageView
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginEnd="@dimen/app_common_page_horizontal_padding"
+            android:src="@drawable/icon_voice_ai_menu"
+            app:layout_constraintBottom_toBottomOf="@+id/v_tool_bar"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintEnd_toEndOf="@+id/v_tool_bar"
+            app:layout_constraintTop_toTopOf="@+id/v_tool_bar"
+            app:layout_constraintWidth_percent="0.0666666666666667" />
+
+        <androidx.core.widget.NestedScrollView
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/v_tool_bar">
+
+            <androidx.constraintlayout.widget.ConstraintLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+                <Space
+                    android:id="@+id/space1"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    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"
+                    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" />
+
+                <Space
+                    android:id="@+id/sapce3"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    app:layout_constraintDimensionRatio="360:12"
+                    app:layout_constraintTop_toBottomOf="@+id/sapce2" />
+
+                <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: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/sapce3" />
+
+
+                <Space
+                    android:id="@+id/sapce4"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    app:layout_constraintDimensionRatio="360:12"
+                    app:layout_constraintTop_toBottomOf="@+id/tv_your_txt_title" />
+
+                <View
+                    android:id="@+id/v_voice_print_bg"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
+                    android:background="@drawable/bg_voice_ai"
+                    app:layout_constraintDimensionRatio="336:148"
+                    app:layout_constraintTop_toBottomOf="@+id/sapce4" />
+
+                <com.atmob.voiceai.widget.IgnoreNoEnterActionEditText
+                    android:layout_width="0dp"
+                    android:layout_height="0dp"
+                    android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
+                    android:layout_marginTop="@dimen/app_common_page_horizontal_padding"
+                    android:layout_marginBottom="8dp"
+                    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"
+                    android:textSize="14sp"
+                    app:layout_constraintBottom_toTopOf="@+id/tv_print_clear"
+                    app:layout_constraintEnd_toEndOf="@+id/v_voice_print_bg"
+                    app:layout_constraintStart_toStartOf="@+id/v_voice_print_bg"
+                    app:layout_constraintTop_toTopOf="@+id/v_voice_print_bg" />
+
+                <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: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" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginEnd="@dimen/app_common_page_horizontal_padding"
+                    android:text="@{voiceAIViewModel.voicePrintLimitTxt}"
+                    android:textColor="@color/white50"
+                    android:textSize="14sp"
+                    app:layout_constraintBottom_toBottomOf="@+id/tv_print_clear"
+                    app:layout_constraintEnd_toEndOf="@+id/v_voice_print_bg"
+                    app:layout_constraintTop_toTopOf="@+id/tv_print_clear"
+                    tools:text="0/200" />
+
+                <Space
+                    android:id="@+id/space5"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    app:layout_constraintDimensionRatio="360:30"
+                    app:layout_constraintTop_toBottomOf="@+id/v_voice_print_bg" />
+
+                <TextView
+                    android:id="@+id/tv_all_voice"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+                    android:text="@string/voice_all"
+                    android:textColor="@color/white"
+                    android:textSize="16sp"
+                    android:textStyle="bold"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toBottomOf="@+id/space5" />
+
+
+                <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.core.widget.NestedScrollView>
+
+        <View
+            android:id="@+id/v_generate"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:background="@drawable/bg_voice_generate"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="360:76" />
+
+        <View
+            android:id="@+id/v_generate_btn"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_marginHorizontal="@dimen/app_common_page_horizontal_padding"
+            android:background="@drawable/bg_voice_ai_btn"
+            android:onClick="@{()-> voiceAIViewModel.onGenerateClick()}"
+            app:layout_constraintBottom_toBottomOf="@+id/v_generate"
+            app:layout_constraintDimensionRatio="336:48"
+            app:layout_constraintTop_toTopOf="@+id/v_generate" />
+
+        <ImageView
+            android:id="@+id/iv_ad"
+            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"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="6dp"
+            android:text="@string/voice_ai_generate"
+            android:textColor="@color/colorPrimary"
+            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.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>
+</layout>

+ 3 - 9
app/src/main/res/values/colors.xml

@@ -1,16 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <color name="colorPrimary">#2B66FE</color>
-    <color name="colorClickPrimary">#579AFF</color>
-    <color name="colorPrimaryVariant">#E0EBFF</color>
-
+    <color name="colorPrimary">#151718</color>
+    <color name="colorPrimaryVariant">#06D6A0</color>
     <color name="transparent">#00FFFFFF</color>
-
     <color name="common_txt_color">#202020</color>
-    <color name="main_tab_name_text_color">#999999</color>
-    <color name="tab_un_select_text_color">#666666</color>
-    <color name="item_data_checked_color">#F2F2F2</color>
-    <color name="color_404040">#404040</color>
+    <color name="voice_free_crux_txt_color">#FFEF5F</color>
 
 
 </resources>

+ 5 - 0
app/src/main/res/values/dimens.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <dimen name="app_common_page_horizontal_padding">12dp</dimen>
+    <dimen name="app_status_bar_height">24dp</dimen>
+</resources>

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

@@ -3,4 +3,13 @@
     <string name="main_pager_voice_ai">Voice AI</string>
     <string name="main_pager_clone_voice">Clone Voice</string>
     <string name="main_pager_history">History</string>
+    <string name="voice_pro">Pro</string>
+    <string name="voice_ai">Voice AI</string>
+    <string name="voice_your_text">Your text</string>
+    <string name="voice_ai_clear_txt">Clear text</string>
+    <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>
 </resources>

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

@@ -10,7 +10,7 @@
         <!-- Status bar color. -->
         <item name="android:statusBarColor">@android:color/transparent</item>
         <!-- Customize your theme here. -->
-
+        <item name="android:windowBackground">@color/colorPrimary</item>
         <item name="toolbarStyle">@style/tool_bar_style</item>
 
         <item name="toolbarNavigationButtonStyle">@style/myToolbarNavigationButtonStyle</item>