Browse Source

创建项目

zk 2 years ago
commit
94d953994f
55 changed files with 1283 additions and 0 deletions
  1. 6 0
      app/.gitignore
  2. 162 0
      app/build.gradle
  3. BIN
      app/keystore/voiceAI.jks
  4. 21 0
      app/proguard-rules.pro
  5. 45 0
      app/src/main/AndroidManifest.xml
  6. 60 0
      app/src/main/java/com/atmob/voiceai/App.java
  7. 6 0
      app/src/main/java/com/atmob/voiceai/data/api/AtmobApi.java
  8. 22 0
      app/src/main/java/com/atmob/voiceai/data/api/request/BaseRequest.java
  9. 17 0
      app/src/main/java/com/atmob/voiceai/data/consts/Constants.java
  10. 5 0
      app/src/main/java/com/atmob/voiceai/data/consts/ErrorCode.java
  11. 38 0
      app/src/main/java/com/atmob/voiceai/di/NetworkModule.java
  12. 9 0
      app/src/main/java/com/atmob/voiceai/module/clonevoice/CloneVoiceFragment.java
  13. 9 0
      app/src/main/java/com/atmob/voiceai/module/history/HistoryFragment.java
  14. 116 0
      app/src/main/java/com/atmob/voiceai/module/main/MainActivity.java
  15. 94 0
      app/src/main/java/com/atmob/voiceai/module/main/MainPagerAdapter.java
  16. 17 0
      app/src/main/java/com/atmob/voiceai/module/main/MainViewModel.java
  17. 27 0
      app/src/main/java/com/atmob/voiceai/module/splash/SplashActivity.java
  18. 10 0
      app/src/main/java/com/atmob/voiceai/module/voiceai/VoiceAiFragment.java
  19. 49 0
      app/src/main/java/com/atmob/voiceai/utils/ActivityForResultUtil.java
  20. 23 0
      app/src/main/java/com/atmob/voiceai/utils/BoxingUtil.java
  21. 40 0
      app/src/main/java/com/atmob/voiceai/utils/ToastUtil.java
  22. 5 0
      app/src/main/res/color/selector_main_tab_name.xml
  23. BIN
      app/src/main/res/drawable-xxhdpi/icon_tab_voice_checked.webp
  24. BIN
      app/src/main/res/drawable-xxhdpi/icon_tab_voice_un_check.webp
  25. 15 0
      app/src/main/res/drawable/bg_theme_splash.xml
  26. 170 0
      app/src/main/res/drawable/ic_launcher_background.xml
  27. 30 0
      app/src/main/res/drawable/ic_launcher_foreground.xml
  28. 5 0
      app/src/main/res/drawable/selector_icon_main_tab_clone_voice.xml
  29. 5 0
      app/src/main/res/drawable/selector_icon_main_tab_hirstory.xml
  30. 5 0
      app/src/main/res/drawable/selector_icon_main_tab_voice.xml
  31. 23 0
      app/src/main/res/layout/activity_main.xml
  32. 6 0
      app/src/main/res/layout/activity_splash.xml
  33. 34 0
      app/src/main/res/layout/item_main_tab_layout.xml
  34. 6 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  35. 6 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  36. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.webp
  37. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
  38. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.webp
  39. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
  40. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.webp
  41. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
  42. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
  43. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
  44. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
  45. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
  46. 16 0
      app/src/main/res/values/colors.xml
  47. 6 0
      app/src/main/res/values/strings.xml
  48. 55 0
      app/src/main/res/values/style.xml
  49. 24 0
      app/src/main/res/values/themes.xml
  50. 13 0
      app/src/main/res/xml/backup_rules.xml
  51. 19 0
      app/src/main/res/xml/data_extraction_rules.xml
  52. 40 0
      app/src/main/res/xml/network_config.xml
  53. 18 0
      gradle/libs.versions.toml
  54. BIN
      gradle/wrapper/gradle-wrapper.jar
  55. 6 0
      gradle/wrapper/gradle-wrapper.properties

+ 6 - 0
app/.gitignore

@@ -0,0 +1,6 @@
+/build
+/seeds.txt
+/unused.txt
+/mapping.txt
+/messProguard.txt
+/messMapping.txt

+ 162 - 0
app/build.gradle

@@ -0,0 +1,162 @@
+plugins {
+    id 'com.android.application'
+    id 'dagger.hilt.android.plugin'
+    id 'stringfog'
+}
+
+android {
+    namespace 'com.atmob.voiceai'
+    compileSdk rootProject.compileSdkVersion
+
+    defaultConfig {
+        applicationId rootProject.applicationId
+        minSdk rootProject.minSdkVersion
+        targetSdk rootProject.targetSdkVersion
+        versionCode rootProject.versionCode
+        versionName rootProject.versionName
+
+        ndk {
+            //noinspection ChromeOsAbiSupport
+            abiFilters "arm64-v8a"
+        }
+    }
+
+    signingConfigs {
+        debug {
+            storeFile file("keystore/voiceAI.jks")
+            storePassword "voice888"
+            keyAlias "voice"
+            keyPassword "voice888"
+        }
+        release {
+            storeFile file("keystore/voiceAI.jks")
+            storePassword "voice888"
+            keyAlias "voice"
+            keyPassword "voice888"
+        }
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.release
+
+            buildConfigField "boolean", "isLocalNetwork", "false"
+            buildConfigField "String", "HOST", "\"$prod_host\""
+        }
+
+        debug {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.debug
+
+            buildConfigField "boolean", "isLocalNetwork", "true"
+            buildConfigField "String", "HOST", "\"$test_host\""
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+    buildFeatures {
+        viewBinding true
+        dataBinding true
+    }
+
+    applicationVariants.configureEach { variant ->
+        def date = new Date().format("YYMMddHHmmss")
+        variant.outputs.configureEach {
+            def fileName = "${defaultConfig.applicationId}" +
+                    "-v${defaultConfig.versionName}" +
+                    "-${variant.buildType.name}" +
+                    "-${date}" +
+                    ".apk"
+            outputFileName = fileName
+        }
+    }
+
+    sourceSets {
+        main { jniLibs.srcDirs = ['libs'] }
+    }
+
+    configurations.configureEach {
+        resolutionStrategy {
+            // don't cache changing modules at all
+            cacheChangingModulesFor 10, 'seconds'
+        }
+    }
+}
+
+import com.github.megatronking.stringfog.plugin.kg.RandomKeyGenerator
+
+stringfog {
+    implementation 'com.github.megatronking.stringfog.xor.StringFogImpl'
+    fogPackages = ['com.atmob.voiceai']
+    debug false
+    enable true
+    kg new RandomKeyGenerator()
+    mode base64
+}
+
+dependencies {
+    //jar or aar
+    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
+
+    //Atmob SDK
+    implementation 'extra.common:base:1.0.0-SNAPSHOT'
+    implementation "extra.pack:channel:1.1.0-SNAPSHOT"
+    implementation "extra.common:core:2.0.3-SNAPSHOT" //base utils
+    implementation "extra.common:network:1.1.0-SNAPSHOT"
+    implementation "extra.common:rxjava:1.1.0-SNAPSHOT"
+    implementation "extra.common:user:1.0.1-SNAPSHOT" //get user data(includes device info)
+    implementation("plus.pay:pay:1.1.0-SNAPSHOT") {
+        exclude group: 'third.pay', module: 'ali'
+    }
+    api 'com.alipay.sdk:alipaysdk-android:15.8.16@aar'
+
+    //oaid
+    implementation "extra.common:oaid:1.1.0-SNAPSHOT"
+
+    //AppCompat
+    implementation "androidx.appcompat:appcompat:$rootProject.appcompat_version"
+
+    //Material
+    implementation "com.google.android.material:material:$rootProject.material_version"
+
+    //RecyclerView
+    implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerview_version"
+
+    //ConstraintLayout
+    implementation "androidx.constraintlayout:constraintlayout:$rootProject.constraintlayout_version"
+
+    //Gson
+    implementation "com.google.code.gson:gson:$rootProject.gson_version"
+
+    //Lifecycle
+    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-livedata:$rootProject.lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-reactivestreams:$rootProject.lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-process:$rootProject.lifecycle_version"
+
+    //Hilt
+    implementation "com.google.dagger:hilt-android:$rootProject.hilt_version"
+    annotationProcessor "com.google.dagger:hilt-compiler:$rootProject.hilt_version"
+
+    //Glide
+    implementation "com.github.bumptech.glide:glide:$rootProject.glide_version"
+    annotationProcessor "com.github.bumptech.glide:compiler:$rootProject.glide_version"
+
+    //MMKV
+    implementation "com.tencent:mmkv:$rootProject.mmkv_version"
+
+    //immersionbar
+    implementation "com.gyf.immersionbar:immersionbar:$rootProject.immersionbar_version"
+    implementation "com.gyf.immersionbar:immersionbar-components:$rootProject.immersionbar_version"
+
+    //字符串加密算法
+    implementation "com.github.megatronking.stringfog:xor:$rootProject.stringfog_verstion"
+
+
+}

BIN
app/keystore/voiceAI.jks


+ 21 - 0
app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

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

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.atmob.voiceai">
+
+    <!-- 允许访问网络,必选权限 -->
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:name=".App"
+        android:allowBackup="false"
+        android:dataExtractionRules="@xml/data_extraction_rules"
+        android:fullBackupContent="@xml/backup_rules"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:networkSecurityConfig="@xml/network_config"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.VoiceAI"
+        tools:ignore="LockedOrientationActivity"
+        tools:replace="android:allowBackup"
+        tools:targetApi="32">
+
+
+        <activity
+            android:name=".module.splash.SplashActivity"
+            android:exported="true"
+            android:screenOrientation="portrait"
+            android:theme="@style/Theme.Splash">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".module.main.MainActivity"
+            android:launchMode="singleTask"
+            android:screenOrientation="portrait" />
+    </application>
+
+
+</manifest>

+ 60 - 0
app/src/main/java/com/atmob/voiceai/App.java

@@ -0,0 +1,60 @@
+package com.atmob.voiceai;
+
+import android.content.Context;
+
+import com.atmob.app.lib.base.BaseApplication;
+import com.atmob.user.AtmobUser;
+
+import dagger.hilt.android.HiltAndroidApp;
+
+
+@HiltAndroidApp
+public class App extends BaseApplication {
+
+    private static App INSTANCE;
+
+    public static App getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        INSTANCE = this;
+    }
+
+    @Override
+    protected boolean isDebug() {
+        return BuildConfig.DEBUG;
+    }
+
+    @Override
+    protected String defaultChannel() {
+        return "GooglePlay";
+    }
+
+    @Override
+    protected int defaultAppId() {
+        return 0;
+    }
+
+    @Override
+    protected int defaultTgPlatformId() {
+        return 0;
+    }
+
+    @Override
+    protected int complianceStrategy() {
+        return AtmobUser.GLOBAL;
+    }
+
+    @Override
+    protected void initCommon(boolean b) {
+
+    }
+
+    @Override
+    public void initAfterGrant(boolean b) {
+
+    }
+}

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

@@ -0,0 +1,6 @@
+package com.atmob.voiceai.data.api;
+
+
+public interface AtmobApi {
+
+}

+ 22 - 0
app/src/main/java/com/atmob/voiceai/data/api/request/BaseRequest.java

@@ -0,0 +1,22 @@
+package com.atmob.voiceai.data.api.request;
+
+import com.atmob.user.param.AtmobParams;
+
+public class BaseRequest extends AtmobParams {
+
+
+    public BaseRequest() {
+//        if (BuildConfig.DEBUG) {
+//            try {
+//                Field androidId = AtmobParams.class.getDeclaredField("androidId");
+//                androidId.setAccessible(true);
+//                androidId.set(this, "6713123wdq22e1232");
+//            } catch (NoSuchFieldException e) {
+//
+//            } catch (IllegalAccessException e) {
+//
+//            }
+//        }
+
+    }
+}

+ 17 - 0
app/src/main/java/com/atmob/voiceai/data/consts/Constants.java

@@ -0,0 +1,17 @@
+package com.atmob.voiceai.data.consts;
+
+
+import com.atmob.voiceai.BuildConfig;
+
+public class Constants {
+
+    private static final String Atmob_Server_Base_URL_LOCAL = "http://192.168.10.171:8880";
+    public static final String Atmob_Server_Base_URL_REMOTE = BuildConfig.HOST;
+    public static final String Atmob_Server_Base_URL = BuildConfig.isLocalNetwork ? Atmob_Server_Base_URL_LOCAL : Atmob_Server_Base_URL_REMOTE;
+
+    public static final String PRIVACY_POLICY = "http://cdn.myaskai.cn/manyue/static/wjsjhfds-manyue-a-privacy.html";
+
+    public static final String USER_AGREEMENT = "http://cdn.myaskai.cn/manyue/static/wjsjhfds-manyue-clause.html";
+
+
+}

+ 5 - 0
app/src/main/java/com/atmob/voiceai/data/consts/ErrorCode.java

@@ -0,0 +1,5 @@
+package com.atmob.voiceai.data.consts;
+
+public interface ErrorCode {
+
+}

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

@@ -0,0 +1,38 @@
+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.consts.Constants;
+import com.google.gson.Gson;
+
+import javax.inject.Singleton;
+
+import atmob.okhttp3.OkHttpClient;
+import atmob.retrofit2.Retrofit;
+import atmob.retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
+import atmob.retrofit2.converter.gson.GsonConverterFactory;
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.InstallIn;
+import dagger.hilt.components.SingletonComponent;
+
+@Module
+@InstallIn(SingletonComponent.class)
+public class NetworkModule {
+    private static final String ATMOB_TAG = "AtmobApi";
+
+    @Singleton
+    @Provides
+    public static AtmobApi provideAtmobApi(Gson gson) {
+        OkHttpClient okHttpClient = AtmobOkHttpClient.newInstance(ATMOB_TAG, BuildConfig.DEBUG);
+        return new Retrofit.Builder()
+                .client(okHttpClient)
+                .addConverterFactory(GsonConverterFactory.create(gson))
+                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
+                .baseUrl(Constants.Atmob_Server_Base_URL)
+                .build()
+                .create(AtmobApi.class);
+    }
+
+}

+ 9 - 0
app/src/main/java/com/atmob/voiceai/module/clonevoice/CloneVoiceFragment.java

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

+ 9 - 0
app/src/main/java/com/atmob/voiceai/module/history/HistoryFragment.java

@@ -0,0 +1,9 @@
+package com.atmob.voiceai.module.history;
+
+import com.atmob.app.lib.base.BaseFragment;
+
+import dagger.hilt.android.HiltAndroidApp;
+
+@HiltAndroidApp
+public class HistoryFragment extends BaseFragment {
+}

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

@@ -0,0 +1,116 @@
+package com.atmob.voiceai.module.main;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.atmob.app.lib.base.BaseActivity;
+import com.atmob.voiceai.databinding.ActivityMainBinding;
+import com.atmob.voiceai.databinding.ItemMainTabLayoutBinding;
+import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
+import com.gyf.immersionbar.ImmersionBar;
+
+import dagger.hilt.android.AndroidEntryPoint;
+
+
+@AndroidEntryPoint
+public class MainActivity extends BaseActivity<ActivityMainBinding> {
+
+
+    private MainViewModel mainViewModel;
+
+    private TabLayoutMediator tabLayoutMediator;
+    private MainPagerAdapter mainPagerAdapter;
+
+    public static void start(Context context) {
+        Intent intent = new Intent(context, MainActivity.class);
+        if (!(context instanceof Activity)) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        initView();
+        initObserver();
+    }
+
+    private void initObserver() {
+
+    }
+
+
+    private void initView() {
+        initViewPager();
+        initTabLayout();
+    }
+
+    private void initViewPager() {
+        mainPagerAdapter = new MainPagerAdapter(this);
+        binding.mainViewPager.setAdapter(mainPagerAdapter);
+        binding.mainViewPager.setUserInputEnabled(false);
+        binding.mainViewPager.setOffscreenPageLimit(mainPagerAdapter.getItemCount());
+    }
+
+
+    private void initTabLayout() {
+        binding.mainTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
+            @Override
+            public void onTabSelected(TabLayout.Tab tab) {
+                ItemMainTabLayoutBinding itemBinding = (ItemMainTabLayoutBinding) tab.getTag();
+                if (itemBinding != null) {
+                    itemBinding.tabText.setSelected(true);
+                    itemBinding.tabIcon.setSelected(true);
+                }
+            }
+
+            @Override
+            public void onTabUnselected(TabLayout.Tab tab) {
+                ItemMainTabLayoutBinding itemBinding = (ItemMainTabLayoutBinding) tab.getTag();
+                if (itemBinding != null) {
+                    itemBinding.tabText.setSelected(false);
+                    itemBinding.tabIcon.setSelected(false);
+                }
+            }
+
+            @Override
+            public void onTabReselected(TabLayout.Tab tab) {
+
+            }
+        });
+        tabLayoutMediator = new TabLayoutMediator(binding.mainTabLayout, binding.mainViewPager, true, false, (tab, position) -> {
+            MainPagerAdapter.MainPagerItem mainPagerItem = mainPagerAdapter.getMainPagerItemByPosition(position);
+            ItemMainTabLayoutBinding itemBinding = ItemMainTabLayoutBinding.inflate(getLayoutInflater());
+            itemBinding.tabText.setText(mainPagerItem.getTabName());
+            itemBinding.tabIcon.setImageResource(mainPagerItem.getTabIcon());
+            tab.setCustomView(itemBinding.getRoot());
+            tab.setTag(itemBinding);
+        });
+        tabLayoutMediator.attach();
+    }
+
+    @Override
+    protected void initViewModel() {
+        super.initViewModel();
+        mainViewModel = getViewModelProvider().get(MainViewModel.class);
+    }
+
+    @Override
+    protected void configImmersion(@NonNull ImmersionBar immersionBar) {
+        super.configImmersion(immersionBar);
+        immersionBar.statusBarDarkFont(true);
+    }
+
+    @Override
+    protected boolean shouldImmersion() {
+        return true;
+    }
+}

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

@@ -0,0 +1,94 @@
+package com.atmob.voiceai.module.main;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+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 java.util.Arrays;
+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_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)
+    );
+
+    public MainPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
+        super(fragmentActivity);
+    }
+
+    public int getPosition(Class<? extends Fragment> cls) {
+        if (mainPagerItems == null || mainPagerItems.isEmpty()) {
+            return 0;
+        }
+        for (int i = 0; i < mainPagerItems.size(); i++) {
+            MainPagerItem mainPagerItem = mainPagerItems.get(i);
+            if (mainPagerItem.pagerClass == cls) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    @NonNull
+    @Override
+    public Fragment createFragment(int position) {
+        MainPagerItem mainPagerItem = mainPagerItems.get(position);
+        Class<? extends Fragment> pagerClass = mainPagerItem.getPagerClass();
+        return createFragmentByClass(pagerClass);
+    }
+
+    private Fragment createFragmentByClass(Class<? extends Fragment> pagerClass) {
+        try {
+            return pagerClass.newInstance();
+        } catch (IllegalAccessException | InstantiationException e) {
+            e.printStackTrace();
+        }
+        throw new RuntimeException();
+    }
+
+    @Override
+    public int getItemCount() {
+        return mainPagerItems.size();
+    }
+
+    public MainPagerItem getMainPagerItemByPosition(int position) {
+        if (position < 0 || position >= mainPagerItems.size()) {
+            return null;
+        }
+        return mainPagerItems.get(position);
+    }
+
+    public static class MainPagerItem {
+        private final int tabName;
+        private final int tabIcon;
+        private final Class<? extends Fragment> pagerClass;
+
+        public MainPagerItem(int tabName, int tabIcon, Class<? extends Fragment> pagerClass) {
+            this.tabName = tabName;
+            this.tabIcon = tabIcon;
+            this.pagerClass = pagerClass;
+        }
+
+        public int getTabName() {
+            return tabName;
+        }
+
+        public int getTabIcon() {
+            return tabIcon;
+        }
+
+        public Class<? extends Fragment> getPagerClass() {
+            return pagerClass;
+        }
+    }
+}

+ 17 - 0
app/src/main/java/com/atmob/voiceai/module/main/MainViewModel.java

@@ -0,0 +1,17 @@
+package com.atmob.voiceai.module.main;
+
+import com.atmob.app.lib.base.BaseViewModel;
+
+import javax.inject.Inject;
+
+import dagger.hilt.android.lifecycle.HiltViewModel;
+
+
+@HiltViewModel
+public class MainViewModel extends BaseViewModel {
+
+
+    @Inject
+    public MainViewModel() {
+    }
+}

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

@@ -0,0 +1,27 @@
+package com.atmob.voiceai.module.splash;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+import com.atmob.app.lib.base.BaseActivity;
+import com.atmob.voiceai.databinding.ActivitySplashBinding;
+import com.atmob.voiceai.module.main.MainActivity;
+
+@SuppressLint("CustomSplashScreen")
+public class SplashActivity extends BaseActivity<ActivitySplashBinding> {
+    @Override
+    protected boolean shouldImmersion() {
+        return true;
+    }
+
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        MainActivity.start(this);
+    }
+
+
+}

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

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

+ 49 - 0
app/src/main/java/com/atmob/voiceai/utils/ActivityForResultUtil.java

@@ -0,0 +1,49 @@
+package com.atmob.voiceai.utils;
+
+
+import androidx.activity.ComponentActivity;
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.ActivityResultRegistry;
+import androidx.activity.result.contract.ActivityResultContract;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import java.util.UUID;
+
+public class ActivityForResultUtil<I, O> {
+
+
+    ActivityResultLauncher<I> launcher = null;
+
+
+    public void startActivityForResult(ComponentActivity activity, ActivityResultContract<I, O> contract, I input, ActivityResultCallback<O> callback) {
+        String key = UUID.randomUUID().toString();
+
+        ActivityResultRegistry registry = activity.getActivityResultRegistry();
+        LifecycleEventObserver observer = new LifecycleEventObserver() {
+
+            @Override
+            public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner, @NonNull Lifecycle.Event event) {
+                if (Lifecycle.Event.ON_DESTROY == event) {
+                    if (launcher != null) {
+                        launcher.unregister();
+                    }
+                    activity.getLifecycle().removeObserver(this);
+                }
+            }
+        };
+        activity.getLifecycle().addObserver(observer);
+
+        launcher = registry.register(key, contract, result -> {
+            if (launcher != null) {
+                launcher.unregister();
+            }
+            activity.getLifecycle().removeObserver(observer);
+            callback.onActivityResult(result);
+        });
+        launcher.launch(input);
+    }
+}

+ 23 - 0
app/src/main/java/com/atmob/voiceai/utils/BoxingUtil.java

@@ -0,0 +1,23 @@
+package com.atmob.voiceai.utils;
+
+public class BoxingUtil {
+    private BoxingUtil() {
+
+    }
+
+    public static boolean boxing(Boolean b) {
+        return b != null && b;
+    }
+
+    public static int boxing(Integer integer) {
+        return integer == null ? 0 : integer;
+    }
+
+    public static long boxing(Long l) {
+        return l == null ? 0 : l;
+    }
+
+    public static float boxing(Float f) {
+        return f == null ? 0f : f;
+    }
+}

+ 40 - 0
app/src/main/java/com/atmob/voiceai/utils/ToastUtil.java

@@ -0,0 +1,40 @@
+package com.atmob.voiceai.utils;
+
+import android.widget.Toast;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.StringRes;
+
+import com.atmob.common.runtime.ContextUtil;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * 测试高版本的Android已经不会把Toast堆在一起了, 后期遇到问题再修改此处的实现吧.
+ */
+public class ToastUtil {
+
+    @IntDef(value = {
+            LENGTH_SHORT,
+            LENGTH_LONG
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Duration {
+    }
+
+    public static final int LENGTH_SHORT = 0;
+
+    public static final int LENGTH_LONG = 1;
+
+    private ToastUtil() {
+    }
+
+    public static void show(String message, @Duration int duration) {
+        Toast.makeText(ContextUtil.getContext(), message, duration).show();
+    }
+
+    public static void show(@StringRes int messageRes, @Duration int duration) {
+        Toast.makeText(ContextUtil.getContext(), messageRes, duration).show();
+    }
+}

+ 5 - 0
app/src/main/res/color/selector_main_tab_name.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/white" android:state_selected="true" />
+    <item android:color="@color/white60" />
+</selector>

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


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


+ 15 - 0
app/src/main/res/drawable/bg_theme_splash.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <size
+                android:width="1080px"
+                android:height="1920px" />
+            <gradient
+                android:angle="90"
+                android:endColor="#F8FAFF"
+                android:startColor="#DEE9FF" />
+        </shape>
+    </item>
+
+</layer-list>

+ 170 - 0
app/src/main/res/drawable/ic_launcher_background.xml

@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#3DDC84"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>

File diff suppressed because it is too large
+ 30 - 0
app/src/main/res/drawable/ic_launcher_foreground.xml


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

@@ -0,0 +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" />
+</selector>

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

@@ -0,0 +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" />
+</selector>

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

@@ -0,0 +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" />
+</selector>

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

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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">
+
+    <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_constraintTop_toTopOf="parent" />
+
+    <com.google.android.material.tabs.TabLayout
+        android:id="@+id/main_tab_layout"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:translationZ="10dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintDimensionRatio="360:56"
+        app:tabIconTint="@android:color/transparent"
+        app:tabIndicator="@null" />
+</androidx.constraintlayout.widget.ConstraintLayout>

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

+ 34 - 0
app/src/main/res/layout/item_main_tab_layout.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <ImageView
+        android:id="@+id/tab_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toTopOf="@id/tab_text"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_chainStyle="packed"
+        tools:src="@drawable/icon_tab_voice_checked" />
+
+    <TextView
+        android:id="@+id/tab_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="2dp"
+        android:textColor="@color/selector_main_tab_name"
+        android:textSize="10sp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/tab_icon"
+        tools:ignore="SmallSp"
+        tools:text="Voice AI" />
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 6 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

+ 6 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp


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

@@ -0,0 +1,16 @@
+<?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="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>
+
+
+</resources>

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

@@ -0,0 +1,6 @@
+<resources>
+    <string name="app_name">VoiceAI</string>
+    <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>
+</resources>

+ 55 - 0
app/src/main/res/values/style.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="tool_bar_style" parent="Base.Widget.AppCompat.Toolbar">
+        <item name="contentInsetLeft">0dp</item>
+        <item name="contentInsetStart">0dp</item>
+        <item name="contentInsetStartWithNavigation">0dp</item>
+        <item name="titleTextColor">@color/common_txt_color</item>
+        <item name="titleTextAppearance">@style/Toolbar.TitleText</item>
+    </style>
+
+    <style name="Toolbar.TitleText" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
+        <item name="android:textSize">18sp</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:layout_gravity">center</item>
+        <item name="android:gravity">center</item>
+    </style>
+
+    <style name="myToolbarNavigationButtonStyle" parent="@style/Widget.AppCompat.Toolbar.Button.Navigation">
+        <item name="android:minWidth">0dp</item>
+        <item name="android:paddingLeft">12dp</item>
+    </style>
+
+    <style name="Theme.Common.Dialog" parent="Theme.MaterialComponents.Light.Dialog">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
+        <item name="colorOnPrimary">@color/white</item>
+
+        <!-- Customize your theme here. -->
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:backgroundDimAmount">0.7</item>
+
+        <item name="android:windowAnimationStyle">@style/Animation.CommonDialog</item>
+    </style>
+
+
+    <style name="Animation.CommonDialog" parent="Animation.AppCompat.Dialog">
+        <item name="android:windowEnterAnimation">@anim/anim_alpha_in</item>
+        <item name="android:windowExitAnimation">@anim/anim_alpha_out</item>
+    </style>
+
+
+    <style name="Tool_Bar_Title_Txt">
+        <item name="android:textSize">17sp</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textColor">@color/common_txt_color</item>
+        <item name="android:layout_gravity">center</item>
+    </style>
+
+
+</resources>

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

@@ -0,0 +1,24 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.VoiceAI" parent="Theme.MaterialComponents.Light.NoActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
+        <item name="colorPrimaryDark">@color/colorPrimary</item>
+        <item name="colorAccent">@color/colorPrimary</item>
+        <item name="colorOnPrimary">@color/white</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <!-- Customize your theme here. -->
+
+        <item name="toolbarStyle">@style/tool_bar_style</item>
+
+        <item name="toolbarNavigationButtonStyle">@style/myToolbarNavigationButtonStyle</item>
+    </style>
+
+    <style name="Theme.Splash" parent="Theme.MaterialComponents.Light.NoActionBar">
+        <item name="android:windowBackground">@drawable/bg_theme_splash</item>
+        <item name="android:windowTranslucentStatus">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+    </style>
+</resources>

+ 13 - 0
app/src/main/res/xml/backup_rules.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample backup rules file; uncomment and customize as necessary.
+   See https://developer.android.com/guide/topics/data/autobackup
+   for details.
+   Note: This file is ignored for devices older that API 31
+   See https://developer.android.com/about/versions/12/backup-restore
+-->
+<full-backup-content>
+    <!--
+   <include domain="sharedpref" path="."/>
+   <exclude domain="sharedpref" path="device.xml"/>
+-->
+</full-backup-content>

+ 19 - 0
app/src/main/res/xml/data_extraction_rules.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample data extraction rules file; uncomment and customize as necessary.
+   See https://developer.android.com/about/versions/12/backup-restore#xml-changes
+   for details.
+-->
+<data-extraction-rules>
+    <cloud-backup>
+        <!-- TODO: Use <include> and <exclude> to control what is backed up.
+        <include .../>
+        <exclude .../>
+        -->
+    </cloud-backup>
+    <!--
+    <device-transfer>
+        <include .../>
+        <exclude .../>
+    </device-transfer>
+    -->
+</data-extraction-rules>

+ 40 - 0
app/src/main/res/xml/network_config.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="MissingDefaultResource">
+
+    <!-- For AdColony, this permits all cleartext traffic: -->
+    <base-config cleartextTrafficPermitted="true">
+        <trust-anchors>
+            <certificates src="system" />
+        </trust-anchors>
+    </base-config>
+    <!-- End AdColony section -->
+
+    <domain-config cleartextTrafficPermitted="true">
+
+        <!-- For Meta Audience Network, this permits cleartext traffic to localhost: -->
+        <domain includeSubdomains="true">127.0.0.1</domain>
+        <!-- End Meta Audience Network section -->
+
+    </domain-config>
+
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">192.168.10.244</domain>
+    </domain-config>
+
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">cdn.atmob.com</domain>
+    </domain-config>
+
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">test-micro.atmob.com</domain>
+    </domain-config>
+
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">api-img-sh.fengkongcloud.com</domain>
+    </domain-config>
+
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">api-text-gz.fengkongcloud.com</domain>
+    </domain-config>
+</network-security-config>

+ 18 - 0
gradle/libs.versions.toml

@@ -0,0 +1,18 @@
+[versions]
+agp = "8.3.0"
+junit = "4.13.2"
+junitVersion = "1.1.5"
+espressoCore = "3.5.1"
+appcompat = "1.6.1"
+material = "1.11.0"
+
+[libraries]
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+
+[plugins]
+androidApplication = { id = "com.android.application", version.ref = "agp" }
+

BIN
gradle/wrapper/gradle-wrapper.jar


+ 6 - 0
gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Fri Apr 26 10:28:01 CST 2024
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists