Browse Source

提交人:jtm
提交内容:第一次提交

江天明 2 years ago
parent
commit
e5d7b31a8b
100 changed files with 5301 additions and 0 deletions
  1. 16 0
      .gitignore
  2. 1 0
      BusinessAuth/.gitignore
  3. 20 0
      BusinessAuth/build.gradle
  4. 0 0
      BusinessAuth/consumer-rules.pro
  5. 21 0
      BusinessAuth/proguard-rules.pro
  6. 24 0
      BusinessAuth/src/androidTest/java/com/develop/auth/ExampleInstrumentedTest.kt
  7. 10 0
      BusinessAuth/src/main/AndroidManifest.xml
  8. 141 0
      BusinessAuth/src/main/java/com/develop/auth/ui/MemberAuthActivity.kt
  9. 75 0
      BusinessAuth/src/main/java/com/develop/auth/ui/MemberForgotFragment.kt
  10. 51 0
      BusinessAuth/src/main/java/com/develop/auth/ui/MemberLaunchFragment.kt
  11. 105 0
      BusinessAuth/src/main/java/com/develop/auth/ui/MemberLoginFragment.kt
  12. 134 0
      BusinessAuth/src/main/java/com/develop/auth/ui/MemberProfileFragment.kt
  13. 75 0
      BusinessAuth/src/main/java/com/develop/auth/ui/MemberRegisterFragment.kt
  14. 38 0
      BusinessAuth/src/main/java/com/develop/auth/ui/UserIconSelectDialog.kt
  15. 146 0
      BusinessAuth/src/main/java/com/develop/auth/viewmodel/MemberViewModel.kt
  16. 66 0
      BusinessAuth/src/main/res/layout/activity_member_auth.xml
  17. 118 0
      BusinessAuth/src/main/res/layout/fragment_member_forgot.xml
  18. 60 0
      BusinessAuth/src/main/res/layout/fragment_member_launch.xml
  19. 87 0
      BusinessAuth/src/main/res/layout/fragment_member_login.xml
  20. 120 0
      BusinessAuth/src/main/res/layout/fragment_member_profile.xml
  21. 100 0
      BusinessAuth/src/main/res/layout/fragment_member_register.xml
  22. 17 0
      BusinessAuth/src/test/java/com/develop/auth/ExampleUnitTest.kt
  23. 1 0
      BusinessCommon/.gitignore
  24. 20 0
      BusinessCommon/build.gradle
  25. 0 0
      BusinessCommon/consumer-rules.pro
  26. 21 0
      BusinessCommon/proguard-rules.pro
  27. 24 0
      BusinessCommon/src/androidTest/java/com/develop/common/ExampleInstrumentedTest.kt
  28. 5 0
      BusinessCommon/src/main/AndroidManifest.xml
  29. 216 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/FoodDataProvider.kt
  30. 343 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/DataFactory.kt
  31. 31 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/FoodDatabase.kt
  32. 82 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/ModelKit.kt
  33. 20 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/UserDatabase.kt
  34. 15 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/DevConfigDao.kt
  35. 18 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/FoodConfigDao.kt
  36. 152 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/FoodRecipeDao.kt
  37. 53 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/UserInfoDao.kt
  38. 57 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevAccessory.kt
  39. 40 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevHotTag.kt
  40. 52 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevPortrait.kt
  41. 137 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipe.kt
  42. 40 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeAccessory.kt
  43. 46 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeCategory.kt
  44. 128 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeCookingStep.kt
  45. 70 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeFood.kt
  46. 64 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeNutrition.kt
  47. 52 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipePortionSize.kt
  48. 40 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeRelTag.kt
  49. 46 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeTag.kt
  50. 23 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevVersion.kt
  51. 15 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserFavoriteRecipes.kt
  52. 15 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserHistoryRecipes.kt
  53. 16 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserInfo.kt
  54. 15 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserOnLineRecipes.kt
  55. 16 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserTag.kt
  56. 24 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/Api.kt
  57. 80 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/converter/SerializationConverter.kt
  58. 20 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/interceptor/FoodRequestInterceptor.kt
  59. 17 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/ActivateBody.kt
  60. 20 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/DeviceInfoBody.kt
  61. 16 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/LoginBody.kt
  62. 21 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/PerfectInfoBody.kt
  63. 16 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/RegisterBody.kt
  64. 20 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/ScoreBody.kt
  65. 14 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/SendVerifyCodeBody.kt
  66. 22 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/UpdatePasswordBody.kt
  67. 9 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/CategoryListResult.kt
  68. 79 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/DevInfoResult.kt
  69. 8 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/HotTagsResult.kt
  70. 9 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/LoginResult.kt
  71. 27 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/NoticeResult.kt
  72. 8 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/PerfectInfoResult.kt
  73. 71 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/RecipeDetailResult.kt
  74. 24 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/RecipesListResult.kt
  75. 38 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/RegisterResult.kt
  76. 36 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/ScoreResult.kt
  77. 7 0
      BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/VerifyCodeResult.kt
  78. 44 0
      BusinessCommon/src/main/java/com/develop/common/dialog/AgeSelectDialog.kt
  79. 72 0
      BusinessCommon/src/main/java/com/develop/common/dialog/CancelConfirmDialog.kt
  80. 43 0
      BusinessCommon/src/main/java/com/develop/common/dialog/CommonDialog.kt
  81. 39 0
      BusinessCommon/src/main/java/com/develop/common/dialog/GenderSelectDialog.kt
  82. 28 0
      BusinessCommon/src/main/java/com/develop/common/dialog/LoadingDialog.kt
  83. 84 0
      BusinessCommon/src/main/java/com/develop/common/dialog/PlainDialogView.java
  84. 145 0
      BusinessCommon/src/main/java/com/develop/common/dialog/RecipeUpdateDialog.kt
  85. 15 0
      BusinessCommon/src/main/java/com/develop/common/event/CommonEvent.kt
  86. 182 0
      BusinessCommon/src/main/java/com/develop/common/food_sdk/FloatWindowManager.kt
  87. 21 0
      BusinessCommon/src/main/java/com/develop/common/food_sdk/FoodSdkUtils.kt
  88. 183 0
      BusinessCommon/src/main/java/com/develop/common/food_sdk/GlobalDevEvent.kt
  89. 52 0
      BusinessCommon/src/main/java/com/develop/common/food_sdk/ProtocolListener.kt
  90. 53 0
      BusinessCommon/src/main/java/com/develop/common/food_sdk/SerialPortUtils.kt
  91. 45 0
      BusinessCommon/src/main/java/com/develop/common/router/Screens.kt
  92. 44 0
      BusinessCommon/src/main/java/com/develop/common/tag/CommonTag.kt
  93. 27 0
      BusinessCommon/src/main/java/com/develop/common/ui/CommonBVMActivity.kt
  94. 22 0
      BusinessCommon/src/main/java/com/develop/common/ui/CommonBVMFragment.kt
  95. 176 0
      BusinessCommon/src/main/java/com/develop/common/ui/CommonBindingActivity.kt
  96. 33 0
      BusinessCommon/src/main/java/com/develop/common/ui/CommonBindingFragment.kt
  97. 15 0
      BusinessCommon/src/main/java/com/develop/common/utils/CommonKit.kt
  98. 70 0
      BusinessCommon/src/main/java/com/develop/common/utils/TimeDownUtil.kt
  99. 24 0
      BusinessCommon/src/main/java/com/develop/common/utils/TimeUtil.kt
  100. 0 0
      BusinessCommon/src/main/java/com/develop/common/utils/TimerUtils.kt

+ 16 - 0
.gitignore

@@ -0,0 +1,16 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
+/.idea/

+ 1 - 0
BusinessAuth/.gitignore

@@ -0,0 +1 @@
+/build

+ 20 - 0
BusinessAuth/build.gradle

@@ -0,0 +1,20 @@
+plugins {
+    id 'kotlin-kapt'
+    id 'org.jetbrains.kotlin.android'
+}
+
+apply from: '../common.gradle'
+
+android{
+    sourceSets {
+        main {
+            jniLibs.srcDirs = ['libs']
+        }
+    }
+}
+
+dependencies {
+    api project(path: ':BusinessCommon')
+    kapt 'com.alibaba:arouter-compiler:1.5.2'
+    kapt  "androidx.room:room-compiler:2.4.2"
+}

+ 0 - 0
BusinessAuth/consumer-rules.pro


+ 21 - 0
BusinessAuth/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

+ 24 - 0
BusinessAuth/src/androidTest/java/com/develop/auth/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.develop.auth
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.runner.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.develop.auth.test", appContext.packageName)
+    }
+}

+ 10 - 0
BusinessAuth/src/main/AndroidManifest.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.develop.auth">
+
+    <application>
+        <activity
+            android:launchMode="singleTask"
+            android:name=".ui.MemberAuthActivity" />
+    </application>
+</manifest>

+ 141 - 0
BusinessAuth/src/main/java/com/develop/auth/ui/MemberAuthActivity.kt

@@ -0,0 +1,141 @@
+package com.develop.auth.ui
+
+import android.content.Context
+import android.os.Bundle
+import android.util.SparseArray
+import android.view.LayoutInflater
+import android.view.View
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import com.alibaba.android.arouter.facade.annotation.Autowired
+import com.alibaba.android.arouter.facade.annotation.Route
+import com.alibaba.android.arouter.launcher.ARouter
+import com.develop.auth.R
+import com.develop.auth.databinding.ActivityMemberAuthBinding
+import com.develop.auth.viewmodel.FragmentTag
+import com.develop.auth.viewmodel.MemberViewModel
+import com.develop.base.ext.navigateTo
+import com.develop.base.util.MMkvUtils
+import com.develop.common.router.Screens
+import com.develop.common.tag.LOGIN_TAG
+import com.develop.common.ui.CommonBVMActivity
+import com.develop.common.ui.CommonBVMFragment
+
+@Route(path = Screens.Auth.MEMBER)
+class MemberAuthActivity : CommonBVMActivity<ActivityMemberAuthBinding, MemberViewModel>() {
+    @JvmField
+    @Autowired(name = "enter_from_home")
+    var enterFromHome: Boolean = false
+
+    private val memberForgotFragment = MemberForgotFragment()
+    private val memberLaunchFragment = MemberLaunchFragment()
+    private val memberLoginBinding = MemberLoginFragment()
+    private val memberProfileFragment = MemberProfileFragment()
+    private val memberRegisterFragment = MemberRegisterFragment()
+    private val fragmentMap = HashMap<FragmentTag, Fragment>()
+
+    override fun createViewModel(): MemberViewModel {
+        return getViewModel(MemberViewModel::class.java)
+    }
+
+    override fun createViewBinding(inflater: LayoutInflater): ActivityMemberAuthBinding {
+        return ActivityMemberAuthBinding.inflate(inflater)
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        ARouter.getInstance().inject(this)
+        initFragmentList()
+        viewModel.enterFromHome = enterFromHome
+        binding.ivUserIcon.setOnClickListener {
+            supportFragmentManager.beginTransaction()
+                .add(UserIconSelectDialog(viewModel), "UserIconDialog").commitAllowingStateLoss()
+        }
+        binding.tvIconSelect.setOnClickListener {
+            supportFragmentManager.beginTransaction()
+                .add(UserIconSelectDialog(viewModel), "UserIconDialog").commitAllowingStateLoss()
+        }
+
+        binding.tvSkip.setOnClickListener {
+            navigateTo(Screens.Main.ENTRANCE_CHOSEN)
+            finish()
+        }
+
+
+        supportFragmentManager.registerFragmentLifecycleCallbacks(
+            object : FragmentManager.FragmentLifecycleCallbacks() {
+                override fun onFragmentAttached(
+                    fm: FragmentManager, f: Fragment, context: Context
+                ) {
+                    if (f is MemberProfileFragment) {
+                        binding.clUserIcon.visibility = View.VISIBLE
+                    }
+                }
+
+                override fun onFragmentDetached(fm: FragmentManager, f: Fragment) {
+                    if (f is MemberProfileFragment) {
+                        binding.clUserIcon.visibility = View.GONE
+                    }
+                }
+            }, false
+        )
+
+        viewModel.fragmentChangeLiveData.observe(this) {
+            fragmentMap[it]?.apply {
+                replaceFragment(R.id.fl_container, this)
+            }
+        }
+
+        if (MMkvUtils.getBool(LOGIN_TAG)) {
+            addFragment(
+                R.id.fl_container, memberProfileFragment
+            )
+        } else {
+            addFragment(
+                R.id.fl_container, memberLaunchFragment
+            )
+        }
+
+        viewModel.chooseAvatar.observe(this) {
+            val icon = when (it ?: 0) {
+                0 -> {
+                    com.develop.common.R.drawable.ic_icon1
+                }
+                1 -> {
+                    com.develop.common.R.drawable.ic_icon2
+                }
+                2 -> {
+                    com.develop.common.R.drawable.ic_icon3
+                }
+                3 -> {
+                    com.develop.common.R.drawable.ic_icon4
+                }
+                4 -> {
+                    com.develop.common.R.drawable.ic_icon5
+                }
+                else -> {
+                    com.develop.common.R.drawable.ic_icon6
+                }
+            }
+            binding.ivUserIcon.setImageResource(icon)
+        }
+    }
+
+    private fun initFragmentList() {
+        fragmentMap[FragmentTag.MEMBER_FORGER] = memberForgotFragment
+        fragmentMap[FragmentTag.MEMBER_LAUNCH] = memberLaunchFragment
+        fragmentMap[FragmentTag.MEMBER_LOGIN] = memberLoginBinding
+        fragmentMap[FragmentTag.MEMBER_PROFILE] = memberProfileFragment
+        fragmentMap[FragmentTag.MEMBER_REGISTER] = memberRegisterFragment
+    }
+
+    fun getRootView(): View {
+        return binding.flRoot
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        fragmentMap.clear()
+    }
+}

+ 75 - 0
BusinessAuth/src/main/java/com/develop/auth/ui/MemberForgotFragment.kt

@@ -0,0 +1,75 @@
+package com.develop.auth.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.develop.auth.R
+import com.develop.auth.databinding.FragmentMemberForgotBinding
+import com.develop.auth.viewmodel.FragmentTag
+import com.develop.auth.viewmodel.MemberViewModel
+import com.develop.base.mvvm.BaseBVMFragment
+import com.develop.common.ui.CommonBVMFragment
+import com.drake.net.utils.scopeDialog
+
+class MemberForgotFragment : CommonBVMFragment<FragmentMemberForgotBinding, MemberViewModel>() {
+
+
+    override fun createViewBinding(
+        inflater: LayoutInflater,
+        container: ViewGroup?
+    ): FragmentMemberForgotBinding {
+        return FragmentMemberForgotBinding.inflate(inflater, container, false)
+    }
+
+    override fun onPostCreateView() {
+        super.onPostCreateView()
+        binding.tvLogin.setOnClickListener {
+            viewModel.fragmentChangeLiveData.postValue(FragmentTag.MEMBER_LOGIN)
+        }
+
+        binding.tvSendEmail.setOnClickListener {
+            val email = binding.etEmailId.text.toString()
+            if (email.isEmpty()) {
+                showToast("Please fill in your email")
+                return@setOnClickListener
+            }
+            showPlainDialog()
+            viewModel.sendEmail(email)
+        }
+        binding.tvResetPassword.setOnClickListener {
+            val email = binding.etEmailId.text.toString()
+            val captcha = binding.etCaptcha.text.toString()
+            val password = binding.etPassword.text.toString()
+            if (email.isEmpty()) {
+                showToast("Please fill in your email")
+                return@setOnClickListener
+            }
+            if (captcha.isEmpty()) {
+                showToast("Please fill in the captcha")
+                return@setOnClickListener
+            }
+            if (password.isEmpty()) {
+                showToast("Please fill in the password")
+                return@setOnClickListener
+            }
+            showPlainDialog()
+            viewModel.resetPassword(email, captcha, password)
+        }
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        viewModel.resetPasswordLiveData.observe(viewLifecycleOwner) {
+            dismissPlainDialog()
+            it.msg?.apply {
+                showToast(this)
+            }
+
+        }
+    }
+
+    override fun createViewModel(): MemberViewModel {
+        return getViewModelOfActivity(MemberViewModel::class.java)
+    }
+
+}

+ 51 - 0
BusinessAuth/src/main/java/com/develop/auth/ui/MemberLaunchFragment.kt

@@ -0,0 +1,51 @@
+package com.develop.auth.ui
+
+import android.graphics.Color
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.style.ForegroundColorSpan
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.develop.auth.R
+import com.develop.auth.databinding.FragmentMemberLaunchBinding
+import com.develop.auth.viewmodel.FragmentTag
+import com.develop.auth.viewmodel.MemberViewModel
+import com.develop.base.ext.navigateTo
+import com.develop.base.mvvm.BaseBVMFragment
+import com.develop.common.router.Screens
+import com.develop.common.ui.CommonBVMFragment
+
+class MemberLaunchFragment: CommonBVMFragment<FragmentMemberLaunchBinding, MemberViewModel>() {
+
+    override fun createViewBinding(
+        inflater: LayoutInflater,
+        container: ViewGroup?
+    ): FragmentMemberLaunchBinding {
+        return FragmentMemberLaunchBinding.inflate(inflater, container, false)
+    }
+
+    override fun onPostCreateView() {
+        super.onPostCreateView()
+        val memberText = getString(com.develop.common.R.string.member)
+        val description = getString(com.develop.common.R.string.not_a_member_yet, memberText)
+        val memberIndex = description.indexOf(memberText)
+        val spannable = SpannableString(description)
+        spannable.setSpan(
+            ForegroundColorSpan(Color.RED),
+            memberIndex,
+            memberIndex + memberText.length,
+            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+        )
+        binding.tvTitle.text = spannable
+        binding.tvLoginOrSignup.setOnClickListener {
+            viewModel.fragmentChangeLiveData.postValue(FragmentTag.MEMBER_LOGIN)
+        }
+        binding.tvSkipForNow.setOnClickListener {
+            navigateTo(Screens.Main.ENTRANCE_CHOSEN)
+        }
+    }
+
+    override fun createViewModel(): MemberViewModel {
+        return getViewModelOfActivity(MemberViewModel::class.java)
+    }
+}

+ 105 - 0
BusinessAuth/src/main/java/com/develop/auth/ui/MemberLoginFragment.kt

@@ -0,0 +1,105 @@
+package com.develop.auth.ui
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.blankj.utilcode.util.KeyboardUtils
+import com.develop.auth.R
+import com.develop.auth.databinding.FragmentMemberLoginBinding
+import com.develop.auth.viewmodel.FragmentTag
+import com.develop.auth.viewmodel.MemberViewModel
+import com.develop.base.ext.navigateTo
+import com.develop.base.ext.resId2Dimension
+import com.develop.base.mvvm.BaseBVMFragment
+import com.develop.common.router.Screens
+import com.develop.common.ui.CommonBVMFragment
+
+class MemberLoginFragment : CommonBVMFragment<FragmentMemberLoginBinding, MemberViewModel>(),
+    KeyboardUtils.OnSoftInputChangedListener {
+
+    override fun createViewBinding(
+        inflater: LayoutInflater, container: ViewGroup?
+    ): FragmentMemberLoginBinding {
+        return FragmentMemberLoginBinding.inflate(inflater, container, false)
+    }
+
+    override fun onPostCreateView() {
+        super.onPostCreateView()
+        binding.tvLogin.setOnClickListener {
+            if (!checkInputs()) {
+                return@setOnClickListener
+            }
+            executeLogin(
+                binding.etEmailId.text.toString(), binding.etPassword.text.toString()
+            )
+        }
+        binding.tvRegister.setOnClickListener {
+            viewModel.fragmentChangeLiveData.postValue(FragmentTag.MEMBER_REGISTER)
+        }
+        binding.tvForget.setOnClickListener {
+            viewModel.fragmentChangeLiveData.postValue(FragmentTag.MEMBER_FORGER)
+        }
+        KeyboardUtils.registerSoftInputChangedListener(requireActivity(), this)
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        viewModel.loginLiveData.observe(this) {
+            dismissPlainDialog()
+            it.msg?.apply {
+                showToast(this)
+            }
+            if (it.success) {
+                navigateTo(Screens.Main.ENTRANCE_CHOSEN)
+                hostActivity.finish()
+            }
+        }
+    }
+
+    override fun onSoftInputChanged(height: Int) {
+        val flRoot = (activity as? MemberAuthActivity)?.getRootView() ?: return
+        if (height == 0) {
+            flRoot.translationY = 0f
+            return
+        }
+        val location = IntArray(2)
+        binding.etPassword.getLocationOnScreen(location)
+        val viewBottom = requireActivity().resources.displayMetrics.heightPixels - location[1]
+        val requireDistance = dp60
+        if (viewBottom - height >= requireDistance) {
+            return
+        }
+        val deltaHeight = height - viewBottom + requireDistance
+        flRoot.translationY = -deltaHeight
+        Log.d("SoftInput", "viewBottom:${viewBottom}, height:${height}")
+    }
+
+    private fun checkInputs(): Boolean {
+        val inputEmailId = binding.etEmailId.text.toString()
+        val inputPassword = binding.etPassword.text.toString()
+        return inputEmailId.isNotEmpty() && inputPassword.isNotEmpty()
+    }
+
+    private fun executeLogin(emailId: String, password: String) {
+        showPlainDialog()
+        viewModel.login(
+            emailId, password
+        )
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        KeyboardUtils.unregisterSoftInputChangedListener(requireActivity().window)
+    }
+
+    override fun createViewModel(): MemberViewModel {
+        return getViewModelOfActivity(MemberViewModel::class.java)
+    }
+
+    companion object {
+        var dp60 = (com.develop.base.R.dimen.convert_60px).resId2Dimension()
+    }
+
+}

+ 134 - 0
BusinessAuth/src/main/java/com/develop/auth/ui/MemberProfileFragment.kt

@@ -0,0 +1,134 @@
+package com.develop.auth.ui
+
+import android.graphics.Color
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.lifecycle.MutableLiveData
+import com.develop.auth.databinding.FragmentMemberProfileBinding
+import com.develop.auth.viewmodel.MemberViewModel
+import com.develop.base.ext.navigateTo
+import com.develop.base.ext.resId2Dimension
+import com.develop.base.ext.setVisible
+import com.develop.base.mvvm.BaseBVMFragment
+import com.develop.base.util.ThreadUtils
+import com.develop.common.data_repo.FoodDataProvider
+import com.develop.common.data_repo.db.entity.UserInfo
+import com.develop.common.data_repo.net.model.response.User
+import com.develop.common.dialog.AgeSelectDialog
+import com.develop.common.dialog.GenderSelectDialog
+import com.develop.common.router.Screens
+import com.develop.common.ui.CommonBVMFragment
+
+class MemberProfileFragment : CommonBVMFragment<FragmentMemberProfileBinding, MemberViewModel>() {
+
+    private var selectAge = 0
+    private var selectGender = 2
+
+
+    override fun createViewBinding(
+        inflater: LayoutInflater, container: ViewGroup?
+    ): FragmentMemberProfileBinding {
+        return FragmentMemberProfileBinding.inflate(inflater, container, false)
+    }
+
+    override fun onPostCreateView() {
+        super.onPostCreateView()
+        viewModel.queryUserInfo()
+        binding.tvChooseAge.setOnClickListener {
+            AgeSelectDialog(hostActivity) { index, change ->
+                selectAge = index + 20
+                binding.tvChooseAge.text = selectAge.toString()
+                binding.tvChooseAge.setTextColor(Color.BLACK)
+            }.show()
+        }
+
+        binding.tvChooseSex.setOnClickListener {
+            GenderSelectDialog {
+                selectGender = if (it) 2 else 1
+                if (selectGender == 2) {
+                    binding.tvChooseSex.text = "Male"
+                } else {
+                    binding.tvChooseSex.text = "Female"
+                }
+                binding.tvChooseSex.setTextColor(Color.BLACK)
+            }.show(parentFragmentManager, "gender")
+        }
+        binding.tvSave.setOnClickListener {
+            saveProfile(
+                binding.etNickname.text.toString(),
+                selectAge,
+                selectGender,
+                viewModel.chooseAvatar.value ?: 0
+            )
+        }
+        binding.tvSkipForNow.setOnClickListener {
+            navigateTo(Screens.Main.ENTRANCE_CHOSEN)
+        }
+        binding.tvDestroyAccount.setOnClickListener {
+
+        }
+
+        if (viewModel.enterFromHome) {
+            (binding.tvTitle.layoutParams as ViewGroup.MarginLayoutParams).let {
+                it.topMargin = dp53
+                binding.tvTitle.requestLayout()
+            }
+            (binding.tvSave.layoutParams as ViewGroup.MarginLayoutParams).let {
+                it.topMargin = dp101
+                binding.tvSave.requestLayout()
+            }
+            (binding.tvSkipForNow.layoutParams as ViewGroup.MarginLayoutParams).let {
+                it.topMargin = dp16
+                binding.tvSkipForNow.requestLayout()
+            }
+            binding.tvSkipForNow.text = "Sign out"
+            binding.tvDestroyAccount.setVisible()
+        }
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        viewModel.apply {
+            userInfoLiveData.observe(viewLifecycleOwner) {
+                it?.apply {
+                    selectAge = userAge
+                    selectGender = userGender?.toInt() ?: 2
+                    binding.etNickname.setText(userName ?: "")
+                    viewModel.chooseAvatar.value = userAvatar?.toInt()
+                }
+            }
+            perfectInfoLiveData.observe(viewLifecycleOwner) {
+                dismissPlainDialog()
+                it.msg?.apply {
+                    showToast(this)
+                }
+            }
+        }
+    }
+
+    private fun saveProfile(
+        nickname: String?, age: Int, sex: Int, portrait: Int
+    ) {
+        if (nickname.isNullOrEmpty()) {
+            showToast("Please fill in nickname")
+            return
+        }
+        if (age == 0) {
+            showToast("Please fill in age")
+            return
+        }
+        showPlainDialog(true)
+        viewModel.perfectInfo(nickname, sex.toString(), portrait.toString(), age.toString())
+    }
+
+    override fun createViewModel(): MemberViewModel {
+        return getViewModelOfActivity(MemberViewModel::class.java)
+    }
+
+    companion object {
+        var dp53 = (com.develop.base.R.dimen.convert_53px).resId2Dimension().toInt()
+        var dp101 = (com.develop.base.R.dimen.convert_101px).resId2Dimension().toInt()
+        var dp16 = (com.develop.base.R.dimen.convert_16px).resId2Dimension().toInt()
+    }
+}

+ 75 - 0
BusinessAuth/src/main/java/com/develop/auth/ui/MemberRegisterFragment.kt

@@ -0,0 +1,75 @@
+package com.develop.auth.ui
+
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.develop.auth.R
+import com.develop.auth.databinding.FragmentMemberRegisterBinding
+import com.develop.auth.viewmodel.FragmentTag
+import com.develop.auth.viewmodel.MemberViewModel
+import com.develop.base.mvvm.BaseBVMFragment
+import com.develop.common.ui.CommonBVMFragment
+
+class MemberRegisterFragment : CommonBVMFragment<FragmentMemberRegisterBinding, MemberViewModel>() {
+
+    override fun createViewBinding(
+        inflater: LayoutInflater, container: ViewGroup?
+    ): FragmentMemberRegisterBinding {
+        return FragmentMemberRegisterBinding.inflate(inflater, container, false)
+    }
+
+    override fun onPostCreateView() {
+        super.onPostCreateView()
+        binding.tvRegister.setOnClickListener {
+            if (!checkInputs()) {
+                return@setOnClickListener
+            }
+            executeRegister(
+                binding.etEmailId.text.toString(), binding.etPassword.text.toString()
+            )
+        }
+        binding.tvLogin.setOnClickListener {
+            viewModel.fragmentChangeLiveData.postValue(FragmentTag.MEMBER_LOGIN)
+        }
+
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        viewModel.registerLiveData.observe(viewLifecycleOwner) {
+            dismissPlainDialog()
+            it.msg?.apply {
+                showToast(this)
+            }
+            if (it.success) {
+                viewModel.fragmentChangeLiveData.postValue(FragmentTag.MEMBER_PROFILE)
+            }
+        }
+    }
+
+    private fun checkInputs(): Boolean {
+        val inputEmailId = binding.etEmailId.text.toString()
+        val inputPsd = binding.etPassword.text.toString()
+        val inputPsdConfirm = binding.etPasswordAgain.text.toString()
+        if (inputEmailId.isEmpty() || inputPsd.isEmpty()) {
+            showToast(getString(com.develop.common.R.string.please_fill_in))
+            return false
+        }
+        if (!TextUtils.equals(inputPsd, inputPsdConfirm)) {
+            showToast(getString(com.develop.common.R.string.Password_is_not_the_same))
+            return false
+        }
+        return true
+    }
+
+    private fun executeRegister(emailId: String, password: String) {
+        showPlainDialog()
+        viewModel.register(emailId, password)
+    }
+
+    override fun createViewModel(): MemberViewModel {
+        return getViewModelOfActivity(MemberViewModel::class.java)
+    }
+
+}

+ 38 - 0
BusinessAuth/src/main/java/com/develop/auth/ui/UserIconSelectDialog.kt

@@ -0,0 +1,38 @@
+package com.develop.auth.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.develop.auth.viewmodel.MemberViewModel
+import com.develop.base.mvvm.FullScreenTransparentDialog
+import com.develop.common.databinding.DialogUserIconSelectBinding
+
+class UserIconSelectDialog(var viewModel: MemberViewModel) : FullScreenTransparentDialog() {
+
+    private lateinit var binding: DialogUserIconSelectBinding
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+    ): View {
+        binding = DialogUserIconSelectBinding.inflate(
+            inflater, container, false
+        )
+        binding.ivCancel.setOnClickListener {
+            removeSelf()
+        }
+        settingIconClick(binding.ivIcon1, 0)
+        settingIconClick(binding.ivIcon2, 1)
+        settingIconClick(binding.ivIcon3, 2)
+        settingIconClick(binding.ivIcon4, 3)
+        settingIconClick(binding.ivIcon5, 4)
+        settingIconClick(binding.ivIcon6, 5)
+        return binding.root
+    }
+
+    private fun settingIconClick(view: View, index: Int) {
+        view.setOnClickListener {
+            viewModel.chooseAvatar.value = index
+            removeSelf()
+        }
+    }
+}

+ 146 - 0
BusinessAuth/src/main/java/com/develop/auth/viewmodel/MemberViewModel.kt

@@ -0,0 +1,146 @@
+package com.develop.auth.viewmodel
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.scopeNetLife
+import com.develop.base.mvvm.BaseViewModel
+import com.develop.base.util.MMkvUtils
+import com.develop.common.data_repo.FoodDataProvider
+import com.develop.common.data_repo.db.AuthModel
+import com.develop.common.data_repo.db.entity.UserInfo
+import com.develop.common.data_repo.net.Api
+import com.develop.common.data_repo.net.model.request.*
+import com.develop.common.data_repo.net.model.response.LoginResult
+import com.develop.common.data_repo.net.model.response.PerfectInfoResult
+import com.develop.common.data_repo.net.model.response.RegisterResult
+import com.develop.common.data_repo.net.model.response.VerifyCodeResult
+import com.develop.common.tag.API_TOKEN
+import com.develop.common.tag.CURRENT_USER_ID
+import com.develop.common.tag.CURRENT_USER_ID_TAG
+import com.develop.common.tag.LOGIN_TAG
+import com.drake.net.Post
+import com.develop.base.util.UnPeekLiveData
+
+class MemberViewModel : BaseViewModel() {
+    private var mVerifyCodeKey = ""
+    val chooseAvatar = MutableLiveData<Int>()
+    var enterFromHome: Boolean = false
+
+    var registerLiveData = MutableLiveData<AuthModel>()
+    var loginLiveData = MutableLiveData<AuthModel>()
+    var sendEmailLiveData = MutableLiveData<AuthModel>()
+    var resetPasswordLiveData = MutableLiveData<AuthModel>()
+    var perfectInfoLiveData = MutableLiveData<AuthModel>()
+
+    val userInfoLiveData = MutableLiveData<UserInfo>()
+
+    var fragmentChangeLiveData = MutableLiveData<FragmentTag>()
+
+
+    fun register(email: String, password: String) = scopeNetLife {
+        Post<RegisterResult>(Api.REGISTER) {
+            body = RegisterBody.genRegisterBody(email, password)
+        }.await().apply {
+            login(email, password, true)
+        }
+    }.catch {
+        registerLiveData.postValue(AuthModel(false, it.message))
+    }
+
+
+    fun login(email: String, password: String, isFromRegister: Boolean = false) = scopeNetLife {
+        Post<LoginResult>(Api.LOGIN) {
+            body = LoginBody.genLoginBody(email, password)
+        }.await().apply {
+            MMkvUtils.save(API_TOKEN, token)
+            MMkvUtils.save(LOGIN_TAG, true)
+            MMkvUtils.save(CURRENT_USER_ID_TAG, user.id.toLong())
+            FoodDataProvider.getUserDatabase().runInTransaction {
+                user.apply {
+                    val userInfo = UserInfo(
+                        id.toLong(), account, portrait, gender, age
+                    )
+                    FoodDataProvider.getUserDatabase().userInfoDao().updateUserInfo(userInfo)
+                }
+
+            }
+            if (isFromRegister) {
+                registerLiveData.postValue(AuthModel(true))
+            } else {
+                loginLiveData.postValue(AuthModel(true))
+            }
+        }
+    }.catch {
+        if (isFromRegister) {
+            registerLiveData.postValue(AuthModel(false, it.message))
+        } else {
+            loginLiveData.postValue(AuthModel(false, it.message))
+        }
+    }
+
+    fun sendEmail(email: String) = scopeNetLife {
+        Post<VerifyCodeResult>(Api.SEND_VERIFY_CODE) {
+            body = SendVerifyCodeBody.genSendVerifyCodeBody(email)
+        }.await().apply {
+            mVerifyCodeKey = verifyCodeKey
+            sendEmailLiveData.postValue(AuthModel(true, "Email send"))
+        }
+    }.catch {
+        sendEmailLiveData.postValue(AuthModel(false))
+    }
+
+    fun resetPassword(
+        email: String,
+        captcha: String,
+        password: String
+    ) = scopeNetLife {
+        Post<Any>(Api.UPDATE_PWD) {
+            body = UpdatePasswordBody.genUpdatePasswordBody(
+                email,
+                password,
+                mVerifyCodeKey,
+                captcha
+            )
+        }.await().apply {
+            resetPasswordLiveData.postValue(AuthModel(true, "Reset password success!"))
+        }
+    }.catch {
+        resetPasswordLiveData.postValue(AuthModel(false, it.message))
+    }
+
+
+    fun perfectInfo(nickName: String, sex: String, portrait: String, age: String) = scopeNetLife {
+        Post<PerfectInfoResult>(Api.PERFECT_INFO) {
+            body = PerfectInfoBody.genPerfectInfoBody(nickName, sex, portrait, age)
+        }.await().apply {
+            perfectInfoLiveData.postValue(AuthModel(true, "Save success"))
+            FoodDataProvider.getUserDatabase().runInTransaction {
+                val userInfo = UserInfo(
+                    user.id.toLong(),
+                    user.account,
+                    user.portrait,
+                    user.gender,
+                    user.age
+                )
+                FoodDataProvider.getUserDatabase().userInfoDao().updateUserInfo(userInfo)
+            }
+        }
+    }.catch {
+        perfectInfoLiveData.postValue(AuthModel(false, it.message))
+    }
+
+    fun queryUserInfo() {
+        FoodDataProvider.getUserDatabase().runInTransaction {
+            val result = FoodDataProvider.getUserDatabase().userInfoDao()
+                .queryUserInfoByUserId(CURRENT_USER_ID)
+            userInfoLiveData.postValue(result)
+        }
+    }
+}
+
+enum class FragmentTag {
+    MEMBER_FORGER,
+    MEMBER_LAUNCH,
+    MEMBER_LOGIN,
+    MEMBER_PROFILE,
+    MEMBER_REGISTER
+}

+ 66 - 0
BusinessAuth/src/main/res/layout/activity_member_auth.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+    android:id="@+id/fl_root"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <ImageView
+        android:id="@+id/iv_banner"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/convert_672px"
+        android:background="@drawable/ic_auth_banner"/>
+
+    <TextView
+        android:id="@+id/tv_skip"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/convert_90px"
+        android:layout_gravity="end|top"
+        android:layout_margin="@dimen/convert_36px"
+        android:background="@drawable/bg_skip_text"
+        android:text="HOME >>"
+        android:paddingHorizontal="@dimen/convert_62px"
+        android:gravity="center"
+        android:textSize="@dimen/convert_42px"
+        android:textColor="#FFA627"/>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/cl_user_icon"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/convert_672px"
+        android:visibility="gone">
+
+        <com.google.android.material.imageview.ShapeableImageView
+            android:id="@+id/iv_user_icon"
+            android:layout_width="@dimen/convert_270px"
+            android:layout_height="@dimen/convert_270px"
+            android:layout_marginTop="@dimen/convert_140px"
+            android:background="@drawable/ic_icon1"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent"/>
+
+        <TextView
+            android:id="@+id/tv_icon_select"
+            android:layout_width="@dimen/convert_300px"
+            android:layout_height="@dimen/convert_90px"
+            android:layout_marginTop="@dimen/convert_60px"
+            android:text="Select"
+            android:textColor="#FFA627"
+            android:textSize="@dimen/convert_45px"
+            android:gravity="center"
+            android:background="@drawable/bg_icon_select"
+            app:layout_constraintTop_toBottomOf="@+id/iv_user_icon"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <FrameLayout
+        android:id="@+id/fl_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/convert_672px"/>
+
+</FrameLayout>

+ 118 - 0
BusinessAuth/src/main/res/layout/fragment_member_forgot.xml

@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/convert_36px"
+        android:focusable="true"
+        android:focusableInTouchMode="true">
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/reset_password"
+            android:textColor="#6B6B6B"
+            android:textSize="@dimen/convert_54px"
+            android:layout_marginTop="@dimen/convert_110px"
+            android:layout_marginStart="@dimen/convert_75px"/>
+
+        <EditText
+            android:id="@+id/et_email_id"
+            android:layout_width="match_parent"
+            android:layout_marginStart="@dimen/convert_75px"
+            android:layout_marginEnd="@dimen/convert_75px"
+            android:layout_height="@dimen/convert_120px"
+            android:hint="@string/enter_email_id"
+            android:singleLine="true"
+            android:textSize="@dimen/convert_45px"
+            android:inputType="textEmailAddress"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_77px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/convert_75px"
+            android:layout_marginTop="@dimen/convert_45px">
+
+            <EditText
+                android:id="@+id/et_captcha"
+                android:layout_width="@dimen/convert_600px"
+                android:layout_height="@dimen/convert_120px"
+                android:hint="@string/enter_captcha"
+                android:textSize="@dimen/convert_45px"
+                android:singleLine="true"
+                android:background="@drawable/bg_edit_input"
+                android:paddingHorizontal="@dimen/convert_66px"/>
+
+            <TextView
+                android:id="@+id/tv_send_email"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="#FFA627"
+                android:textSize="@dimen/convert_54px"
+                android:text="@string/send_email"
+                android:layout_gravity="center_vertical|end"/>
+
+        </FrameLayout>
+
+        <EditText
+            android:id="@+id/et_password"
+            android:layout_width="match_parent"
+            android:layout_marginStart="@dimen/convert_75px"
+            android:layout_marginEnd="@dimen/convert_75px"
+            android:layout_height="@dimen/convert_120px"
+            android:hint="@string/enter_password_again"
+            android:textSize="@dimen/convert_45px"
+            android:inputType="textPassword"
+            android:singleLine="true"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_45px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <TextView
+            android:id="@+id/tv_hints"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#E60012"
+            android:textSize="@dimen/convert_39px"
+            android:layout_marginTop="@dimen/convert_77px"
+            android:layout_marginStart="@dimen/convert_141px"
+            android:text="@string/enter_the_captcha_obtained_from_the_mail"/>
+
+        <TextView
+            android:id="@+id/tv_reset_password"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#fff"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/reset_password"
+            android:gravity="center"
+            android:layout_gravity="center_horizontal"
+            android:background="@drawable/bg_orange_button"
+            android:layout_marginTop="@dimen/convert_171px"/>
+
+        <TextView
+            android:id="@+id/tv_login"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#FFA627"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/login"
+            android:gravity="center"
+            android:layout_marginTop="10dp"
+            android:layout_gravity="center_horizontal"/>
+
+    </LinearLayout>
+
+</ScrollView>

+ 60 - 0
BusinessAuth/src/main/res/layout/fragment_member_launch.xml

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#fff">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#000"
+            android:textSize="@dimen/convert_72px"
+            android:text="Not a member yet?"
+            android:textStyle="bold"
+            android:layout_marginTop="@dimen/convert_213px"
+            android:layout_marginStart="@dimen/convert_81px"/>
+
+        <TextView
+            android:id="@+id/tv_subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#000"
+            android:textSize="20dp"
+            android:text="@string/launch_detail"
+            android:lineSpacingExtra="8dp"
+            android:layout_marginTop="40dp"
+            android:layout_marginHorizontal="@dimen/convert_81px"/>
+
+        <TextView
+            android:id="@+id/tv_login_or_signup"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#fff"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/login_sign_up"
+            android:gravity="center"
+            android:layout_gravity="center_horizontal"
+            android:background="@drawable/bg_orange_button"
+            android:layout_marginTop="@dimen/convert_383px"/>
+
+        <TextView
+            android:id="@+id/tv_skip_for_now"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#FFA627"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/skip_for_now"
+            android:gravity="center"
+            android:layout_marginTop="10dp"
+            android:layout_gravity="center_horizontal"/>
+
+    </LinearLayout>
+
+</ScrollView>

+ 87 - 0
BusinessAuth/src/main/res/layout/fragment_member_login.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#fff">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:focusable="true"
+        android:focusableInTouchMode="true">
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/login"
+            android:textColor="#6B6B6B"
+            android:textSize="@dimen/convert_54px"
+            android:layout_marginTop="@dimen/convert_110px"
+            android:layout_marginStart="@dimen/convert_75px"/>
+
+        <TextView
+            android:id="@+id/tv_forget"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#E60012"
+            android:textSize="@dimen/convert_39px"
+            android:text="@string/forgot_password"
+            android:layout_marginEnd="@dimen/convert_75px"
+            android:layout_marginTop="@dimen/convert_71px"
+            android:layout_gravity="end"/>
+
+        <EditText
+            android:id="@+id/et_email_id"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:hint="@string/enter_email_id"
+            android:textSize="@dimen/convert_45px"
+            android:singleLine="true"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_129px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <EditText
+            android:id="@+id/et_password"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:inputType="textPassword"
+            android:hint="@string/enter_password"
+            android:textSize="@dimen/convert_45px"
+            android:singleLine="true"
+            android:digits="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_45px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <TextView
+            android:id="@+id/tv_login"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#fff"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/login"
+            android:gravity="center"
+            android:layout_gravity="center_horizontal"
+            android:background="@drawable/bg_orange_button"
+            android:layout_marginTop="@dimen/convert_243px"/>
+
+        <TextView
+            android:id="@+id/tv_register"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#FFA627"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/register"
+            android:gravity="center"
+            android:layout_marginTop="10dp"
+            android:layout_gravity="center_horizontal"/>
+
+    </LinearLayout>
+
+</ScrollView>

+ 120 - 0
BusinessAuth/src/main/res/layout/fragment_member_profile.xml

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#fff">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:focusable="true"
+        android:focusableInTouchMode="true">
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/nickname"
+            android:textColor="#6B6B6B"
+            android:textSize="@dimen/convert_54px"
+            android:layout_marginTop="@dimen/convert_75px"
+            android:layout_marginStart="@dimen/convert_101px"/>
+
+        <EditText
+            android:id="@+id/et_nickname"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:hint="@string/enter_nickname"
+            android:textSize="@dimen/convert_45px"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_32px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <TextView
+            android:id="@+id/tv_sex"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/sex"
+            android:textColor="#6B6B6B"
+            android:textSize="@dimen/convert_54px"
+            android:layout_marginTop="@dimen/convert_80px"
+            android:layout_marginStart="@dimen/convert_101px"/>
+
+        <TextView
+            android:id="@+id/tv_choose_sex"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textSize="@dimen/convert_45px"
+            android:text="@string/male"
+            android:textColor="#B1B2B2"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_32px"
+            android:gravity="center_vertical"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <TextView
+            android:id="@+id/tv_age"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/age"
+            android:textColor="#6B6B6B"
+            android:textSize="@dimen/convert_54px"
+            android:layout_marginTop="@dimen/convert_77px"
+            android:layout_marginStart="@dimen/convert_101px"/>
+
+        <TextView
+            android:id="@+id/tv_choose_age"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textSize="@dimen/convert_45px"
+            android:text="20"
+            android:textColor="#B1B2B2"
+            android:background="@drawable/bg_edit_input"
+            android:gravity="center_vertical"
+            android:layout_marginTop="@dimen/convert_18px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <TextView
+            android:id="@+id/tv_save"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#fff"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/save"
+            android:gravity="center"
+            android:layout_gravity="center_horizontal"
+            android:background="@drawable/bg_orange_button"
+            android:layout_marginTop="@dimen/convert_119px"/>
+
+        <TextView
+            android:id="@+id/tv_skip_for_now"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="wrap_content"
+            android:textColor="#FFA627"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/skip_for_now"
+            android:gravity="center"
+            android:paddingVertical="@dimen/convert_8px"
+            android:layout_marginTop="@dimen/convert_36px"
+            android:layout_gravity="center_horizontal"/>
+
+        <TextView
+            android:id="@+id/tv_destroy_account"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#E60012"
+            android:textSize="@dimen/convert_39px"
+            android:text="@string/cancellation_of_account"
+            android:gravity="center"
+            android:visibility="gone"
+            android:layout_marginTop="@dimen/convert_16px"
+            android:layout_gravity="center_horizontal"/>
+
+    </LinearLayout>
+
+</ScrollView>

+ 100 - 0
BusinessAuth/src/main/res/layout/fragment_member_register.xml

@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#fff">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:focusable="true"
+        android:focusableInTouchMode="true">
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/sign_up_it_s_free"
+            android:textColor="#6B6B6B"
+            android:textSize="@dimen/convert_54px"
+            android:layout_marginTop="@dimen/convert_110px"
+            android:layout_marginStart="@dimen/convert_75px"/>
+
+        <EditText
+            android:id="@+id/et_email_id"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:hint="@string/enter_email_id"
+            android:textSize="@dimen/convert_45px"
+            android:singleLine="true"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_74px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <EditText
+            android:id="@+id/et_password"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:hint="@string/enter_password"
+            android:textSize="@dimen/convert_45px"
+            android:singleLine="true"
+            android:digits="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+            android:inputType="textPassword"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_47px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <EditText
+            android:id="@+id/et_password_again"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:inputType="textPassword"
+            android:hint="@string/enter_password_again"
+            android:textSize="@dimen/convert_45px"
+            android:singleLine="true"
+            android:digits="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+            android:background="@drawable/bg_edit_input"
+            android:layout_marginTop="@dimen/convert_47px"
+            android:layout_gravity="center_horizontal"
+            android:paddingHorizontal="@dimen/convert_66px"/>
+
+        <TextView
+            android:layout_width="@dimen/convert_905px"
+            android:layout_height="wrap_content"
+            android:textColor="#E60012"
+            android:textSize="@dimen/convert_39px"
+            android:text="@string/pwd_requirement"
+            android:layout_marginTop="@dimen/convert_48px"
+            android:lineSpacingExtra="@dimen/convert_20px"
+            android:layout_gravity="center_horizontal"/>
+
+        <TextView
+            android:id="@+id/tv_register"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#fff"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/register"
+            android:gravity="center"
+            android:layout_gravity="center_horizontal"
+            android:background="@drawable/bg_orange_button"
+            android:layout_marginTop="@dimen/convert_87px"/>
+
+        <TextView
+            android:id="@+id/tv_login"
+            android:layout_width="@dimen/convert_930px"
+            android:layout_height="@dimen/convert_120px"
+            android:textColor="#FFA627"
+            android:textSize="@dimen/convert_54px"
+            android:text="@string/login"
+            android:gravity="center"
+            android:layout_marginTop="10dp"
+            android:layout_gravity="center_horizontal"/>
+
+    </LinearLayout>
+
+</ScrollView>

+ 17 - 0
BusinessAuth/src/test/java/com/develop/auth/ExampleUnitTest.kt

@@ -0,0 +1,17 @@
+package com.develop.auth
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+    @Test
+    fun addition_isCorrect() {
+        assertEquals(4, 2 + 2)
+    }
+}

+ 1 - 0
BusinessCommon/.gitignore

@@ -0,0 +1 @@
+/build

+ 20 - 0
BusinessCommon/build.gradle

@@ -0,0 +1,20 @@
+plugins {
+    id 'kotlin-kapt'
+    id 'org.jetbrains.kotlin.android'
+    id 'kotlinx-serialization'
+}
+
+apply from: '../common.gradle'
+
+android{
+    sourceSets {
+        main {
+            jniLibs.srcDirs = ['libs']
+        }
+    }
+}
+
+dependencies {
+    api project(path: ':libBase')
+    kapt  "androidx.room:room-compiler:2.4.2"
+}

+ 0 - 0
BusinessCommon/consumer-rules.pro


+ 21 - 0
BusinessCommon/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

+ 24 - 0
BusinessCommon/src/androidTest/java/com/develop/common/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.develop.common
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.runner.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.develop.common.test", appContext.packageName)
+    }
+}

+ 5 - 0
BusinessCommon/src/main/AndroidManifest.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.develop.common">
+
+</manifest>

+ 216 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/FoodDataProvider.kt

@@ -0,0 +1,216 @@
+package com.develop.common.data_repo
+
+import android.app.Application
+import android.os.Environment
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.room.Room
+import com.blankj.utilcode.util.FileUtils
+import com.blankj.utilcode.util.ToastUtils
+import com.blankj.utilcode.util.ZipUtils
+import com.develop.base.BuildConfig
+import com.develop.base.app.BaseApp
+import com.develop.base.ext.globalApp
+import com.develop.base.util.FileKit
+import com.develop.base.util.GlobalToast
+import com.develop.base.util.ThreadUtils
+import com.develop.common.data_repo.db.FoodDatabase
+import com.develop.common.data_repo.db.UserDatabase
+import com.drake.net.utils.scope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.io.File
+import java.util.concurrent.CountDownLatch
+
+/**
+ * 全局管理数据
+ */
+object FoodDataProvider {
+    private val SYSTEM_MODE = BuildConfig.DEBUG
+    private val RES_DST_PARENT = if (SYSTEM_MODE) {
+        Environment.getExternalStorageDirectory()
+    } else {
+        globalApp().externalCacheDir!!
+    }
+    private var foodDatabase: FoodDatabase? = null
+    private var userDatabase: UserDatabase? = null
+    private var prepareLiveData = MutableLiveData<Boolean>()
+    private val preparedLock = CountDownLatch(1)
+    private val RES_DST_PATH = File(RES_DST_PARENT, "cofa_cooking")
+
+    /**预先准备好菜品资源包数据*/
+    fun prepareData(application: Application) {
+        var isSuccess = true
+        ThreadUtils.runOnWorkThread({
+            if (RES_DST_PATH.exists()) {
+                validateDatabaseFile()
+                preparedLock.countDown()
+            } else {
+                val allFiles = RES_DST_PARENT.listFiles() ?: emptyArray()
+                var targetZipFile: File? = null
+                for (file in allFiles) {
+                    if (file.isDirectory) {
+                        continue
+                    }
+                    if (file.name.endsWith("cofa_cooking.zip")) {
+                        targetZipFile = file
+                        break
+                    }
+                }
+                if (targetZipFile == null) {
+                    FileKit.copyAssetsFile(
+                        application,
+                        "cofa_cooking.zip",
+                        File(RES_DST_PARENT, "cofa_cooking.zip").absolutePath
+                    )
+                    targetZipFile = File(RES_DST_PARENT, "cofa_cooking.zip")
+                }
+                try {
+                    val start = System.currentTimeMillis()
+                    ZipUtils.unzipFile(targetZipFile, RES_DST_PARENT)
+                    Log.d(
+                        "FoodDataProvider", "cost time:${System.currentTimeMillis() - start}"
+                    )
+                    validateDatabaseFile()
+                } catch (ex: Exception) {
+                    ex.printStackTrace()
+                    Log.d("FoodDataProvider", "${ex.message.toString()}")
+                    isSuccess = false
+                }
+                if (isSuccess) {
+                    prepareLiveData.postValue(true)
+                    Log.d("FoodDataProvider", "数据解压成功!")
+                } else {
+                    GlobalToast.showToast("数据包解压失败! 请检查数据包")
+                    prepareLiveData.postValue(false)
+                }
+                preparedLock.countDown()
+            }
+        })
+    }
+
+    /**作兼容处理, 资源包里的图片格式可能是jpg或png*/
+    fun getImagePath(relativePath: String?): String {
+        if (relativePath?.startsWith("http") == true) {
+            return relativePath
+        }
+        preparedLock.await()
+        if (relativePath == null) {
+            return ""
+        }
+        val resFile = getResource(relativePath)
+        if (resFile.exists()) {
+            return resFile.absolutePath
+        }
+        return if (relativePath.endsWith("png")) {
+            "$RES_DST_PATH/${relativePath.replace("png", "jpg")}"
+        } else {
+            "$RES_DST_PATH/${relativePath.replace("jpg", "png")}"
+        }
+    }
+
+    /**根据菜品number删除对应资源文件*/
+    fun deleteRecipeResource(recipeNum: String) {
+        val relPath = "_data/recipe/${recipeNum}"
+        val dir = File(RES_DST_PATH, relPath)
+        if (dir.exists()) {
+            try {
+                FileUtils.delete(dir)
+            } catch (ex: Exception) {
+                ex.printStackTrace()
+            }
+        }
+    }
+
+    /**删除菜品资源包*/
+    fun deleteAll() {
+        if (RES_DST_PATH.exists()) {
+            try {
+                FileUtils.delete(RES_DST_PATH)
+            } catch (ex: Exception) {
+                ex.printStackTrace()
+            }
+        }
+    }
+
+    /**根据菜品number获取configJson文件*/
+    fun getResourceConfigJsonPath(recipeNum: String): File {
+        val relPath = "_data/recipe/${recipeNum}/data.json"
+        return File(RES_DST_PATH, relPath)
+    }
+
+    /**判断菜品number对应的configJson文件是否存在*/
+    fun isResourceDownload(recipeNum: String): Boolean {
+        return getResourceConfigJsonPath(recipeNum).exists()
+    }
+
+    /**获取菜品资源包文件*/
+    fun getExtRecipeResourceDir(): File {
+        return RES_DST_PARENT
+    }
+
+    /**获取菜品图片路径*/
+    fun getResourcePath(relativePath: String?): String {
+        if (relativePath?.startsWith("http") == true) {
+            return relativePath
+        }
+        preparedLock.await()
+        return "$RES_DST_PARENT/$relativePath"
+    }
+
+    private fun getResource(relativePath: String): File {
+        preparedLock.await()
+        return File(RES_DST_PATH, relativePath)
+    }
+
+    private fun validateDatabaseFile() {
+        val dbFile = RES_DST_PATH.listFiles { it ->
+            it.name.endsWith(".db")
+        }
+        if (dbFile.isNullOrEmpty()) {
+            ToastUtils.showShort("数据包文件结构有误, 请检查数据包")
+            prepareLiveData.postValue(false)
+        } else {
+            Log.d("FoodDataProvider", "数据包校验成功")
+            prepareLiveData.postValue(true)
+        }
+
+    }
+
+    fun getPrepareLiveData(): LiveData<Boolean> {
+        return prepareLiveData
+    }
+
+    @Synchronized
+    fun getDatabase(): FoodDatabase {
+        if (foodDatabase != null) {
+            return foodDatabase!!
+        }
+        preparedLock.await()
+        val dbFile = File(RES_DST_PATH, "sqlite.db")
+        foodDatabase = Room.databaseBuilder(
+            BaseApp.application, FoodDatabase::class.java, "sqlite.db"
+        ).allowMainThreadQueries().createFromFile(dbFile).build()
+        return foodDatabase!!
+    }
+
+    @Synchronized
+    fun getUserDatabase(): UserDatabase {
+        if (userDatabase != null) {
+            return userDatabase!!
+        }
+        userDatabase = Room.databaseBuilder(
+            BaseApp.application, UserDatabase::class.java, "userInfo"
+        ).allowMainThreadQueries().build()
+        return userDatabase!!
+    }
+
+    fun checkDataExit(): Boolean {
+        val result = prepareLiveData.value == true
+        if (!result) {
+            prepareData(globalApp())
+        }
+        return prepareLiveData.value == true
+    }
+}

+ 343 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/DataFactory.kt

@@ -0,0 +1,343 @@
+package com.develop.common.data_repo.db
+
+import android.content.res.Resources
+import com.develop.common.R
+import com.develop.common.data_repo.db.entity.DevRecipe
+import com.develop.common.data_repo.db.entity.UserFavoriteRecipes
+
+
+object DataFactory {
+
+    fun createLanguageData(resource: Resources): MutableList<LanguageModel> {
+        val languageList = mutableListOf<LanguageModel>()
+        val strList = mutableListOf<String>(
+            resource.getString(R.string.english),
+            resource.getString(R.string.chinese),
+            resource.getString(R.string.france),
+            resource.getString(R.string.japan)
+        )
+        val iconList = mutableListOf<Int>(
+            R.drawable.ic_english,
+            R.drawable.ic_chinese,
+            R.drawable.ic_france,
+            R.drawable.ic_japan
+        )
+        val typeList = mutableListOf<LanguageType>(
+            LanguageType.English,
+            LanguageType.Chinese,
+            LanguageType.France,
+            LanguageType.Japan
+        )
+        for (i in strList.indices) {
+            languageList.add(LanguageModel(iconList[i], strList[i], typeList[i]))
+        }
+
+        return languageList
+    }
+
+    val modesTypeList = mutableListOf(
+        ModesType.ADAPTED_COOKING,
+        ModesType.WIGHT,
+        ModesType.BOIL_WATER,
+        ModesType.CHOP,
+        ModesType.SLOW_COOK,
+        ModesType.KNEAD_TOUGH,
+        ModesType.STEAM,
+        ModesType.FOOD_PROCESSOR,
+        ModesType.TURBO
+    )
+
+    fun genGridModesList(resource: Resources): MutableList<ModelsModel> {
+        val result = mutableListOf<ModelsModel>()
+        val resIdList = mutableListOf(
+            R.drawable.ic_adapted_cooking,
+            R.drawable.ic_scales,
+            R.drawable.ic_boil_water,
+            R.drawable.ic_chop,
+            R.drawable.ic_slow_cook,
+            R.drawable.ic_knead_dough,
+            R.drawable.ic_steam,
+            R.drawable.ic_food_processor,
+            R.drawable.ic_turbo
+        )
+        val modeNameList = mutableListOf(
+            resource.getString(R.string.adapted_cooking),
+            resource.getString(R.string.wight),
+            resource.getString(R.string.boil_water),
+            resource.getString(R.string.chop),
+            resource.getString(R.string.slow_cook),
+            resource.getString(R.string.knead_dough),
+            resource.getString(R.string.steam),
+            resource.getString(R.string.food_processor),
+            resource.getString(R.string.turbo)
+        )
+
+        for (i in resIdList.indices) {
+            result.add(ModelsModel(resIdList[i], modeNameList[i], modesTypeList[i]))
+        }
+        return result
+    }
+
+    fun genGalleryModesList(resource: Resources): MutableList<ModelsModel> {
+        val result = mutableListOf<ModelsModel>()
+        val resIdList = mutableListOf(
+            R.drawable.ic_grid_adapted_cooking,
+            R.drawable.ic_grid_weight,
+            R.drawable.ic_grid_boil_water,
+            R.drawable.ic_grid_chop,
+            R.drawable.ic_grid_slow_cook,
+            R.drawable.ic_grid_knead_dough,
+            R.drawable.ic_grid_steam,
+            R.drawable.ic_grid_food_processor,
+            R.drawable.ic_grid_turbo
+        )
+        val modeNameList = mutableListOf(
+            resource.getString(R.string.adapted_cooking),
+            resource.getString(R.string.wight),
+            resource.getString(R.string.boil_water),
+            resource.getString(R.string.chop),
+            resource.getString(R.string.slow_cook),
+            resource.getString(R.string.knead_dough),
+            resource.getString(R.string.steam),
+            resource.getString(R.string.food_processor),
+            resource.getString(R.string.turbo)
+        )
+        for (i in resIdList.indices) {
+            result.add(ModelsModel(resIdList[i], modeNameList[i], modesTypeList[i]))
+        }
+        return result
+    }
+
+    fun genTestNewsList(): MutableList<NewsModel> {
+        val result = mutableListOf<NewsModel>()
+        for (i in 0..4) {
+            result.add(
+                NewsModel(
+                    "Good News!",
+                    "The scattergun approach to marketing means that the campaign is not targeted at particular individuals.",
+                    false
+                )
+            )
+        }
+        return result
+    }
+
+    fun genSettingModesList(resource: Resources): MutableList<SettingModel> {
+        val result = mutableListOf<SettingModel>()
+        val resIdList = mutableListOf(
+            R.drawable.ic_setting_language,
+            R.drawable.ic_setting_wifi,
+            R.drawable.ic_setting_voice,
+            R.drawable.ic_setting_brightness,
+            R.drawable.ic_setting_user,
+            R.drawable.ic_setting_folder,
+            R.drawable.ic_setting_reset,
+            R.drawable.ic_setting_about,
+
+            )
+        val nameList = mutableListOf(
+            resource.getString(R.string.language),
+            resource.getString(R.string.wifi),
+            resource.getString(R.string.sound),
+            resource.getString(R.string.brightness),
+            resource.getString(R.string.user_account),
+            resource.getString(R.string.storage),
+            resource.getString(R.string.reset),
+            resource.getString(R.string.about)
+
+        )
+        val settingTypeList = mutableListOf(
+            SettingType.LANGUAGE,
+            SettingType.WIFI,
+            SettingType.SOUND,
+            SettingType.BRIGHTNESS,
+            SettingType.USER_ACCOUNT,
+            SettingType.STORAGE,
+            SettingType.RESTORE_FACTORY_SETTINGS,
+            SettingType.ABOUT
+        )
+        for (i in resIdList.indices) {
+            result.add(SettingModel(resIdList[i], nameList[i], settingTypeList[i]))
+        }
+        return result
+    }
+
+    fun genLocalRecipes(
+        categoryName: String,
+        recipesList: MutableList<DevRecipe>,
+        favoriteRecipes: MutableList<UserFavoriteRecipes>,
+        starList: MutableList<Int>,
+        sortedType: SortedType
+    ): MutableList<Any> {
+        val result = mutableListOf<Any>()
+        val bannerList = mutableListOf<HomeBannerModel>()
+        for (i in 0 until 3) {
+            bannerList.add(HomeBannerModel(R.drawable.ic_auth_banner, ""))
+        }
+        result.add(HomeBannerListModel(bannerList))
+        result.add(FilterSortModel(""))
+        result.add(categoryName)
+        val favoriteRecipesIds = mutableListOf<String>()
+        favoriteRecipes.forEach {
+            favoriteRecipesIds.add(it.favoriteRecipesId)
+        }
+        recipesList.sortWith(Comparator { t, t2 ->
+            when (sortedType) {
+                SortedType.Popular -> {
+                    if ((t.useNum ?: 0) > (t2.useNum ?: 0)) {
+                        return@Comparator -1
+                    } else {
+                        return@Comparator 1
+                    }
+                }
+                SortedType.Newest -> {
+                    if ((t.updateTime ?: 0L) > (t2.updateTime ?: 0L)) {
+                        return@Comparator 1
+                    } else {
+                        return@Comparator -1
+                    }
+
+                }
+                SortedType.Score -> {
+                    val score1 = t.score?.toInt() ?: 0
+                    val score2 = t2.score?.toInt() ?: 0
+                    if (score1 > score2) {
+                        return@Comparator 1
+                    } else {
+                        return@Comparator -1
+                    }
+                }
+            }
+        })
+        for (i in recipesList.indices) {
+            val recipes = recipesList[i]
+            result.add(
+                FoodContentModel(
+                    recipes.photoPath ?: "",
+                    recipes.name ?: "",
+                    recipes.score?.toInt() ?: 0,
+                    getTime(recipes.makeHours ?: 0, recipes.makeMinutes ?: 0),
+                    recipes.difficultyLevel ?: "",
+                    isLike = favoriteRecipesIds.contains(recipes.number),
+                    foodId = recipes.number ?: "",
+                    isNetRecipes = false,
+                    hasDownloaded = false,
+                    recipesEdition = recipes.edition,
+                    useNum = recipes.useNum?.toInt() ?: 0
+                )
+            )
+        }
+        return result
+    }
+
+    fun genSortNameList(resource: Resources): MutableList<FilterSortModel> {
+        val result = mutableListOf<FilterSortModel>()
+        val sortNameList = mutableListOf(
+            resource.getString(R.string.most_popular), resource.getString(R.string.newest), "rating"
+        )
+        for (name in sortNameList) {
+            result.add(FilterSortModel(name))
+        }
+        return result
+    }
+
+    fun genTestSearchDataList(): MutableList<Any> {
+        val result = mutableListOf<Any>()
+        result.add(FilterSortModel(""))
+        val searchNameList =
+            mutableListOf("Guacamole", "Aioli", "Popular", "Chinese food", "Healthy")
+        val searchModelList = mutableListOf<CommonSearchItem>()
+        searchNameList.forEach {
+            searchModelList.add(CommonSearchItem(it))
+        }
+        result.add(CommonSearchModel(searchModelList))
+        return result
+    }
+
+    fun genOnLineHotTags(hotTags: MutableList<String>): MutableList<Any> {
+        val result = mutableListOf<Any>()
+        result.add(FilterSortModel(""))
+        val searchModelList = mutableListOf<CommonSearchItem>()
+        hotTags.forEach {
+            searchModelList.add(CommonSearchItem(it))
+        }
+        result.add(CommonSearchModel(searchModelList))
+        return result
+    }
+
+
+    fun genNetRecipesData(
+        categoryName: String,
+        recipesList: MutableList<DevRecipe>,
+        favoriteRecipes: MutableList<UserFavoriteRecipes>,
+        sortedType: SortedType
+    ): MutableList<Any> {
+        val result = mutableListOf<Any>()
+        result.add(FilterSortModel(""))
+        result.add(categoryName)
+        val favoriteRecipesIds = mutableListOf<String>()
+        favoriteRecipes.forEach {
+            favoriteRecipesIds.add(it.favoriteRecipesId)
+        }
+        recipesList.sortWith(Comparator { t, t2 ->
+            when (sortedType) {
+                SortedType.Popular -> {
+                    if ((t.useNum ?: 0) > (t2.useNum ?: 0)) {
+                        return@Comparator -1
+                    } else {
+                        return@Comparator 1
+                    }
+                }
+                SortedType.Newest -> {
+                    if ((t.updateTime ?: 0L) > (t2.updateTime ?: 0L)) {
+                        return@Comparator 1
+                    } else {
+                        return@Comparator -1
+                    }
+
+                }
+                SortedType.Score -> {
+                    val score1 = t.score?.toInt() ?: 0
+                    val score2 = t2.score?.toInt() ?: 0
+                    if (score1 > score2) {
+                        return@Comparator 1
+                    } else {
+                        return@Comparator -1
+                    }
+                }
+            }
+        })
+
+        for (i in recipesList.indices) {
+            val recipes = recipesList[i]
+            result.add(
+                FoodContentModel(
+                    recipes.photoPath ?: "",
+                    recipes.name ?: "",
+                    recipes.score?.toInt() ?: 0,
+                    getTime(recipes.makeHours ?: 0, recipes.makeMinutes ?: 0),
+                    recipes.difficultyLevel ?: "",
+                    isLike = favoriteRecipesIds.contains(recipes.number),
+                    foodId = recipes.number ?: "",
+                    isNetRecipes = true,
+                    hasDownloaded = false,
+                    recipesEdition = recipes.edition,
+                    useNum = recipes.useNum?.toInt() ?: 0
+                )
+            )
+        }
+        return result
+    }
+}
+
+fun getTime(hour: Int, minute: Int): String {
+    var hourStr = ""
+    var minuteStr = ""
+    if (hour != 0) {
+        hourStr = "${hour}hour"
+    }
+    if (minute != 0) {
+        minuteStr = "${minute}minute"
+    }
+    return "$hourStr$minuteStr"
+}

+ 31 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/FoodDatabase.kt

@@ -0,0 +1,31 @@
+package com.develop.common.data_repo.db
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+import com.develop.common.data_repo.db.dao.FoodConfigDao
+import com.develop.common.data_repo.db.dao.FoodRecipeDao
+import com.develop.common.data_repo.db.entity.*
+
+@Database(
+    entities = [
+        DevAccessory::class,
+        DevHotTag::class,
+        DevPortrait::class,
+        DevRecipe::class,
+        DevRecipeAccessory::class,
+        DevRecipeCategory::class,
+        DevRecipeCookingStep::class,
+        DevRecipeFood::class,
+        DevRecipeNutrition::class,
+        DevRecipePortionSize::class,
+        DevRecipeRelTag::class,
+        DevRecipeTag::class
+    ], version = 1, exportSchema = false
+)
+abstract class FoodDatabase : RoomDatabase() {
+
+    abstract fun recipeDao(): FoodRecipeDao
+
+    abstract fun configDao(): FoodConfigDao
+
+}

+ 82 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/ModelKit.kt

@@ -0,0 +1,82 @@
+package com.develop.common.data_repo.db
+
+
+data class ModelsModel(var resId: Int, var modeName: String, var modesType: ModesType)
+data class NewsModel(var title: String, var des: String, var hasRead: Boolean)
+data class SettingModel(var resId: Int, var name: String, var type: SettingType)
+data class FilterSortModel(var name: String)
+data class HomeBannerListModel(var data: MutableList<HomeBannerModel>)
+data class HomeBannerModel(var cover: Any, var zipUrl: String)
+data class CommonSearchModel(var data: MutableList<CommonSearchItem>)
+data class CommonSearchItem(var name: String)
+data class CategoryModel(var allSize: Int, var recipesSize: Int, var ingredientSize: Int)
+data class LanguageModel(var icon: Int, var languageName: String, var type: LanguageType)
+data class FoodContentModel(
+    var cover: Any,
+    var foodName: String,
+    var starCount: Int,
+    var time: String,
+    var level: String,
+    var isNetRecipes: Boolean = false,
+    var hasDownloaded: Boolean = false,
+    var isLike: Boolean = false,
+    var foodId: String = "",
+    var recipesEdition: String? = "1.0",
+    var useNum: Int = 0
+)
+
+data class AuthModel(var success: Boolean, var msg: String? = null)
+
+//====================枚举=============================//
+enum class LanguageType {
+    English,
+    Chinese,
+    France,
+    Japan
+}
+
+enum class FunType {
+    Modes,
+    LocalRecipes,
+    NetRecipes
+}
+
+enum class ModesType {
+    ADAPTED_COOKING,
+    WIGHT,
+    BOIL_WATER,
+    CHOP,
+    SLOW_COOK,
+    KNEAD_TOUGH,
+    STEAM,
+    FOOD_PROCESSOR,
+    TURBO
+}
+
+enum class SettingType {
+    LANGUAGE,
+    WIFI,
+    SOUND,
+    BRIGHTNESS,
+    USER_ACCOUNT,
+    STORAGE,
+    ABOUT,
+    RESTORE_FACTORY_SETTINGS
+}
+
+enum class CategoryType {
+    All,
+    Recipes,
+    Ingredients
+}
+
+enum class SortedType {
+    Popular,
+    Newest,
+    Score
+}
+
+enum class RecipesType {
+    ONLINE,
+    LOCAL
+}

+ 20 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/UserDatabase.kt

@@ -0,0 +1,20 @@
+package com.develop.common.data_repo.db
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+import com.develop.common.data_repo.db.dao.DevConfigDao
+import com.develop.common.data_repo.db.dao.UserInfoDao
+import com.develop.common.data_repo.db.entity.*
+
+@Database(
+    entities = [DevVersion::class, UserInfo::class, UserFavoriteRecipes::class, UserHistoryRecipes::class, UserTag::class, UserOnLineRecipes::class],
+    version = 1,
+    exportSchema = false
+)
+abstract class UserDatabase : RoomDatabase() {
+
+    abstract fun userInfoDao(): UserInfoDao
+
+    abstract fun devConfigDao(): DevConfigDao
+
+}

+ 15 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/DevConfigDao.kt

@@ -0,0 +1,15 @@
+package com.develop.common.data_repo.db.dao
+import androidx.room.*
+import com.develop.common.data_repo.db.entity.DevVersion
+
+@Dao
+interface DevConfigDao {
+
+
+    @Query("select * from cc_dev_version order by id desc limit 0,1")
+    fun recipeVersion(): DevVersion
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun saveDevVersion(devVersion: DevVersion)
+
+}

+ 18 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/FoodConfigDao.kt

@@ -0,0 +1,18 @@
+package com.develop.common.data_repo.db.dao
+
+import androidx.lifecycle.LiveData
+import androidx.room.*
+import com.develop.common.data_repo.db.entity.DevHotTag
+import com.develop.common.data_repo.db.entity.DevPortrait
+
+@Dao
+interface FoodConfigDao {
+
+    @Query("select * from cc_dev_hot_tag")
+    fun queryHotTag(): LiveData<List<DevHotTag>>
+
+    @Query("select * from cc_dev_portrait")
+    fun queryPortrait(): LiveData<List<DevPortrait>>
+
+
+}

+ 152 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/FoodRecipeDao.kt

@@ -0,0 +1,152 @@
+package com.develop.common.data_repo.db.dao
+
+import androidx.lifecycle.LiveData
+import androidx.room.*
+import com.develop.base.util.MMkvUtils
+import com.develop.common.data_repo.db.entity.*
+
+
+@Dao
+interface FoodRecipeDao {
+    companion object {
+        const val CURRENT_LANGUAGE = "CURRENT_LANGUAGE"
+    }
+    @Query("select * from cc_dev_recipe where lang = :language")
+    fun queryAllRecipe(
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipe>
+
+    @Query("select * from cc_dev_recipe where number = :recipeNumber and lang = :language")
+    fun queryRecipe(
+        recipeNumber: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): DevRecipe?
+
+    @Query("select * from cc_dev_recipe where recipe_category_number = :categoryNumber and lang = :language ")
+    fun queryRecipesByCategory(
+        categoryNumber: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipe>
+
+    @Query("select * from cc_dev_recipe where name LIKE '%' || :name || '%' and lang =:language")
+    fun queryRecipeByName(
+        name: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipe>
+
+    @Query("select * from cc_dev_recipe_accessory where recipe_number = :recipeNumber")
+    fun queryAccessoryIds(recipeNumber: String): List<DevRecipeAccessory>
+
+    @Query("select * from cc_dev_accessory where number = :accessoryNumber and lang = :language")
+    fun queryAccessory(
+        accessoryNumber: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): DevAccessory?
+
+    @Query("select * from cc_dev_recipe_category where lang = :language")
+    fun queryCategory(
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipeCategory>
+
+    @Query("select * from cc_dev_recipe_cooking_step where recipe_number = :recipeNumber and lang = :language")
+    fun queryCookingStep(
+        recipeNumber: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipeCookingStep>
+
+    @Query("select * from cc_dev_recipe_food where recipe_number = :recipeNumber and lang = :language")
+    fun queryFood(
+        recipeNumber: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipeFood>
+
+    @Query("select * from cc_dev_recipe_food where food_name = :foodName and lang = :language")
+    fun queryFoodByFoodName(
+        foodName: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipeFood>
+
+    @Query("select * from cc_dev_recipe_nutrition where recipe_number = :recipeNumber and lang = :language")
+    fun queryNutrition(
+        recipeNumber: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipeNutrition>
+
+    @Query("select * from cc_dev_recipe_portion_size where recipe_number = :recipeNumber and lang = :language")
+    fun queryPortionSize(
+        recipeNumber: String,
+        language: String = MMkvUtils.getString(CURRENT_LANGUAGE) ?: "EN"
+    ): List<DevRecipePortionSize>
+
+    @Query("select * from cc_dev_recipe_rel_tag")
+    fun queryRelTag(): LiveData<List<DevRecipeRelTag>>
+
+    @Query("select * from cc_dev_recipe_tag")
+    fun queryFoodTag(): LiveData<List<DevRecipeTag>>
+
+    @Delete
+    fun deleteRecipe(recipe: DevRecipe)
+
+    @Query("delete from cc_dev_recipe  where number=:recipeNumber")
+    fun deleteRecipe(recipeNumber: String)
+
+    /**
+     * =======================INSERT METHODS=============================
+     */
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipes(data: List<DevRecipe>)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevAccessorys(data: List<DevAccessory>)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertHotTags(data: List<DevHotTag>)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevPortraits(data: List<DevPortrait>)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipeAccessorys(data: List<DevRecipeAccessory>)
+
+    @Query("delete from cc_dev_recipe_accessory  where recipe_number=:recipeNumber")
+    fun deleteDevRecipeAccessorys(recipeNumber: String);
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipeCategorys(data: List<DevRecipeCategory>)
+
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipeCookingSteps(data: List<DevRecipeCookingStep>)
+
+    @Query("delete from cc_dev_recipe_cooking_step  where recipe_number=:recipeNumber")
+    fun deleteDevRecipeCookingSteps(recipeNumber: String)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipeFoods(data: List<DevRecipeFood>)
+
+    @Query("delete from cc_dev_recipe_food  where recipe_number=:recipeNumber")
+    fun deleteDevRecipeFoods(recipeNumber: String)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipeNutritions(data: List<DevRecipeNutrition>)
+
+    @Query("delete from cc_dev_recipe_nutrition  where recipe_number=:recipeNumber")
+    fun deleteDevRecipeNutritions(recipeNumber: String)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipePortionSizes(data: List<DevRecipePortionSize>)
+
+    @Query("delete from cc_dev_recipe_portion_size  where recipe_number=:recipeNumber")
+    fun deleteDevRecipePortionSizes(recipeNumber: String)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipeRelTags(data: List<DevRecipeRelTag>)
+
+    @Query("delete from cc_dev_recipe_rel_tag  where recipe_number=:recipeNumber")
+    fun deleteDevRecipeRelTags(recipeNumber: String)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertDevRecipeTags(data: List<DevRecipeTag>)
+
+
+}

+ 53 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/dao/UserInfoDao.kt

@@ -0,0 +1,53 @@
+package com.develop.common.data_repo.db.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import com.develop.common.data_repo.db.entity.*
+
+@Dao
+interface UserInfoDao {
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun updateUserInfo(userInfo: UserInfo)
+
+    @Query("select * from user_info")
+    fun queryUserInfo(): List<UserInfo>
+
+    @Query("select * from user_info where userId =:userId")
+    fun queryUserInfoByUserId(userId: Long): UserInfo?
+
+    @Query("select * from user_history_recipes where userId =:userId")
+    fun queryHistoryRecipes(userId: Long): List<UserHistoryRecipes>
+
+    @Query("select * from user_favorite_recipes where userId =:userId")
+    fun queryFavoriteRecipes(userId: Long): List<UserFavoriteRecipes>
+
+    @Insert
+    fun insertHistoryRecipe(historyRecipes: UserHistoryRecipes)
+
+    @Insert
+    fun insertFavoriteRecipe(favoriteRecipes: UserFavoriteRecipes)
+
+    @Query("Delete from user_history_recipes where historyRecipesId =:historyRecipeId and userId = :userId")
+    fun removeHistoryRecipe(userId: Long, historyRecipeId: String)
+
+    @Query("Delete from user_favorite_recipes where favoriteRecipesId =:favoriteRecipeId and userId = :userId")
+    fun removeFavoriteRecipe(userId: Long, favoriteRecipeId: String)
+
+    @Query("select * from user_tag where userId = :userId and recipesId =:recipesId")
+    fun queryUserTag(userId: Long, recipesId: String): UserTag?
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun updateUserTag(userTag: UserTag)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun insertOnlineRecipe(onLineRecipes: UserOnLineRecipes)
+
+    @Query("Delete from user_online_recipes where onLineRecipesId =:onLineRecipesId and userId = :userId")
+    fun removeOnlineRecipe(userId: Long, onLineRecipesId: String)
+
+    @Query("select * from user_online_recipes")
+    fun queryUserOnLineRecipesIds(): List<UserOnLineRecipes>
+}

+ 57 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevAccessory.kt

@@ -0,0 +1,57 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * AccessoryName
+ * 配件名称
+ * @author elber
+ * @date 2022/6/15 11:21
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_accessory")
+data class DevAccessory(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+    /**
+     * 配件编码
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 语言编码
+     */
+    @ColumnInfo
+    val lang: String?,
+
+    /**
+     * 名称
+     */
+    @ColumnInfo
+    val name: String?,
+
+    /**
+     * 照片code
+     */
+    @ColumnInfo
+    val photo: String?,
+
+    /**
+     * 照片路径
+     */
+    @ColumnInfo(name = "photo_path")
+    val photoPath: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 40 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevHotTag.kt

@@ -0,0 +1,40 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * HotTag
+ * 热门标签
+ * @author elber
+ * @date 2022/6/16 14:48
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_hot_tag")
+data class DevHotTag(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 序号
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 标签编号
+     */
+    @ColumnInfo(name = "tag_number")
+    val tagNumber: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 52 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevPortrait.kt

@@ -0,0 +1,52 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * Portrait
+ * 用户头像
+ * @author elber
+ * @date 2022/6/15 11:51
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_portrait")
+data class DevPortrait(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 编码
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 照片code
+     */
+    @ColumnInfo
+    val photo: String?,
+
+    /**
+     * 照片路径
+     */
+    @ColumnInfo(name = "photo_path")
+    val photoPath: String?,
+
+    /**
+     * 性别
+     */
+    @ColumnInfo
+    val gender: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 137 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipe.kt

@@ -0,0 +1,137 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * Recipe
+ * 食谱
+ * @author elber
+ * @date 2022/6/16 16:20
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe")
+data class DevRecipe(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 编码
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 当前版本
+     */
+    @ColumnInfo
+    val edition: String?,
+
+    /**
+     * 默认语言
+     */
+    @ColumnInfo
+    val lang: String?,
+
+    /**
+     * 照片编码
+     */
+    @ColumnInfo
+    val photo: String?,
+
+    /**
+     * 照片路径
+     */
+    @ColumnInfo(name = "photo_path")
+    val photoPath: String?,
+
+    /**
+     * 准备小时
+     */
+    @ColumnInfo(name = "prepare_hours")
+    val prepareHours: Int?,
+
+    /**
+     * 准备分钟
+     */
+    @ColumnInfo(name = "prepare_minutes")
+    val prepareMinutes: Int?,
+
+    /**
+     * 制作小时
+     */
+    @ColumnInfo(name = "make_hours")
+    val makeHours: Int?,
+
+    /**
+     * 制作分钟
+     */
+    @ColumnInfo(name = "make_minutes")
+    val makeMinutes: Int?,
+
+    /**
+     * 休息小时
+     */
+    @ColumnInfo(name = "rest_hours")
+    val restHours: Int?,
+
+    /**
+     * 休息分钟
+     */
+    @ColumnInfo(name = "rest_minutes")
+    val restMinutes: Int?,
+
+    /**
+     * 食谱分类序号
+     */
+    @ColumnInfo(name = "recipe_category_number")
+    val recipeCategoryNumber: String?,
+
+    /**
+     * 难度等级
+     * @see com.kuyuntech.cofarcooking.coreapi.constant.core.DifficultyLevel
+     */
+    @ColumnInfo(name = "difficulty_level")
+    val difficultyLevel: String?,
+
+    /**
+     * 兼容母包版本
+     */
+    @ColumnInfo(name = "compatible_version")
+    val compatibleVersion: String?,
+
+    /**
+     * 名称
+     */
+    @ColumnInfo
+    val name: String?,
+
+    /**
+     * 介绍
+     */
+    @ColumnInfo
+    val introduction: String?,
+
+    /**
+     * 评分
+     */
+    @ColumnInfo
+    val score: Double?,
+
+    /**
+     * 使用次数
+     */
+    @ColumnInfo(name = "use_num")
+    val useNum: Long?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 40 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeAccessory.kt

@@ -0,0 +1,40 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipeAccessory
+ * 食谱配件
+ * @author elber
+ * @date 2022/6/16 22:13
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_accessory")
+data class DevRecipeAccessory(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 食谱编号
+     */
+    @ColumnInfo(name = "recipe_number")
+    val recipeNumber: String?,
+
+    /**
+     * 配件编号
+     */
+    @ColumnInfo(name = "accessory_number")
+    val accessoryNumber: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 46 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeCategory.kt

@@ -0,0 +1,46 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipeCategoryName
+ * 食谱分类名称
+ * @author elber
+ * @date 2022/6/16 14:36
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_category")
+data class DevRecipeCategory(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 分类序号
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 名称
+     */
+    @ColumnInfo
+    val name: String?,
+
+    /**
+     * 语言编码
+     */
+    @ColumnInfo
+    val lang: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?,
+)

+ 128 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeCookingStep.kt

@@ -0,0 +1,128 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipeCookingSteps
+ * 食谱烹饪步骤
+ * @author elber
+ * @date 2022/6/16 18:38
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_cooking_step")
+data class DevRecipeCookingStep(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 食谱编号
+     */
+    @ColumnInfo(name = "recipe_number")
+    val recipeNumber: String?,
+
+    /**
+     * 序号
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 工作模式
+     * @see com.kuyuntech.cofarcooking.coreapi.constant.core.RecipeCookingStepsWorkMode
+     */
+    @ColumnInfo(name = "work_mode")
+    val workMode: String?,
+
+    /**
+     * 视频或图片文件标识
+     */
+    @ColumnInfo(name = "photo_video_file_code")
+    val photoVideoFileCode: String?,
+
+    /**
+     * 视频或图片文件路径
+     */
+    @ColumnInfo(name = "photo_video_file_path")
+    val photoVideoFilePath: String?,
+
+    /**
+     * 音频文件标识
+     */
+    @ColumnInfo(name = "audio_file_code")
+    val audioFileCode: String?,
+
+    /**
+     * 音频文件路径
+     */
+    @ColumnInfo(name = "audio_file_path")
+    val audioFilePath: String?,
+
+    /**
+     * 制作模式
+     * @see com.kuyuntech.cofarcooking.coreapi.constant.core.RecipeCookingStepsMakeMode
+     */
+    @ColumnInfo(name = "make_mode")
+    val makeMode: String?,
+
+    /**
+     * 是否自动开始
+     */
+    @ColumnInfo(name = "auto_start")
+    val autoStart: String?,
+
+    /**
+     * 加热温度
+     */
+    @ColumnInfo
+    val temperature: Int?,
+
+    /**
+     * 旋转方向
+     * @see com.kuyuntech.cofarcooking.coreapi.constant.core.RotateDirection
+     */
+    @ColumnInfo(name = "rotate_direction")
+    val rotateDirection: String?,
+
+    /**
+     * 旋转速度
+     */
+    @ColumnInfo(name = "rotate_speed")
+    val rotateSpeed: Int?,
+
+    /**
+     * 工作时间(分)
+     */
+    @ColumnInfo
+    val minute: Int?,
+
+    /**
+     * 工作时间(秒)
+     */
+    @ColumnInfo
+    val second: Int?,
+
+    /**
+     * 描述
+     */
+    @ColumnInfo
+    val description: String?,
+
+    /**
+     * 语言
+     */
+    @ColumnInfo
+    val lang: String?,
+
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 70 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeFood.kt

@@ -0,0 +1,70 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipeFood
+ * 食材
+ * @author elber
+ * @date 2022/6/16 18:14
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_food")
+data class DevRecipeFood(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 序号
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 份量
+     */
+    @ColumnInfo
+    val amount: Double?,
+
+    /**
+     * 食谱编号
+     */
+    @ColumnInfo(name = "recipe_number")
+    val recipeNumber: String?,
+
+    /**
+     * 语言
+     */
+    @ColumnInfo
+    val lang: String?,
+
+    /**
+     * 单位
+     */
+    @ColumnInfo
+    val unit: String?,
+
+    /**
+     * 食材名称
+     */
+    @ColumnInfo(name = "food_name")
+    val foodName: String?,
+
+    /**
+     * 关联食谱份量
+     */
+    @ColumnInfo(name = "recipe_portion_size_number")
+    val recipePortionSizeNumber: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 64 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeNutrition.kt

@@ -0,0 +1,64 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipeNutrition
+ * 食谱营养
+ * @author elber
+ * @date 2022/6/16 22:25
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_nutrition")
+data class DevRecipeNutrition(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 食谱编号
+     */
+    @ColumnInfo(name = "recipe_number")
+    val recipeNumber: String?,
+
+    /**
+     * 序号
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 含量
+     */
+    @ColumnInfo
+    val amount: Double?,
+
+    /**
+     * 单位
+     */
+    @ColumnInfo
+    val unit: String?,
+
+    /**
+     * 营养名称
+     */
+    @ColumnInfo(name = "nutrition_name")
+    val nutritionName: String?,
+
+    /**
+     * 语言
+     */
+    @ColumnInfo
+    val lang: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 52 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipePortionSize.kt

@@ -0,0 +1,52 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipePortionSize
+ * 食谱用料量
+ * @author elber
+ * @date 2022/6/16 18:09
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_portion_size")
+data class DevRecipePortionSize(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 食谱编号
+     */
+    @ColumnInfo(name = "recipe_number")
+    val recipeNumber: String?,
+
+    /**
+     * 序号
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 份量
+     */
+    @ColumnInfo(name = "portion_size")
+    val portionSize: String?,
+
+    /**
+     * 语言
+     */
+    @ColumnInfo
+    val lang: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 40 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeRelTag.kt

@@ -0,0 +1,40 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipeRelTag
+ * 食谱关联标签
+ * @author elber
+ * @date 2022/6/16 23:12
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_rel_tag")
+data class DevRecipeRelTag(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 食谱编号
+     */
+    @ColumnInfo(name = "recipe_number")
+    val recipeNumber: String?,
+
+    /**
+     * 标签编号
+     */
+    @ColumnInfo(name = "tag_number")
+    val tagNumber: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 46 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevRecipeTag.kt

@@ -0,0 +1,46 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * RecipeTagName
+ * 食谱标签名称
+ * @author elber
+ * @date 2022/6/15 17:54
+ * @since 0.0.1
+ */
+@Serializable
+@Entity(tableName = "cc_dev_recipe_tag")
+data class DevRecipeTag(
+
+    @PrimaryKey
+    @ColumnInfo
+    var code: String,
+
+    /**
+     * 名称
+     */
+    @ColumnInfo
+    val name: String?,
+
+    /**
+     * 标签编号
+     */
+    @ColumnInfo
+    val number: String?,
+
+    /**
+     * 语言编码
+     */
+    @ColumnInfo
+    val lang: String?,
+
+    @ColumnInfo(name = "update_time")
+    val updateTime: Long?,
+
+    @ColumnInfo(name = "create_time")
+    val createTime: Long?
+)

+ 23 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/DevVersion.kt

@@ -0,0 +1,23 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+/**
+ * DevVersion
+ * 设备版本表
+ */
+@Serializable
+@Entity(tableName = "cc_dev_version")
+data class DevVersion(
+
+    @PrimaryKey(autoGenerate = true)
+    val id:Long?,
+
+    @ColumnInfo(name = "recipe_update_time")
+    var recipeUpdateTime: Long?,
+
+
+)

+ 15 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserFavoriteRecipes.kt

@@ -0,0 +1,15 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+@Serializable
+@Entity(tableName = "user_favorite_recipes")
+data class UserFavoriteRecipes(
+    var userId: Long,
+    var favoriteRecipesId: String, //喜欢的菜谱id
+    @PrimaryKey(autoGenerate = true)
+    var id: Long = 0,
+) {
+}

+ 15 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserHistoryRecipes.kt

@@ -0,0 +1,15 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+@Serializable
+@Entity(tableName = "user_history_recipes")
+data class UserHistoryRecipes(
+    var userId: Long,
+    var historyRecipesId: String, //历史菜谱id
+    @PrimaryKey(autoGenerate = true)
+    var id: Long = 0,
+) {
+}

+ 16 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserInfo.kt

@@ -0,0 +1,16 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+@Serializable
+@Entity(tableName = "user_info")
+data class UserInfo(
+    @PrimaryKey
+    var userId: Long,
+    var userName: String?,
+    var userAvatar: String?,
+    var userGender: String?,
+    var userAge: Int
+)

+ 15 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserOnLineRecipes.kt

@@ -0,0 +1,15 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+@Serializable
+@Entity(tableName = "user_online_recipes")
+data class UserOnLineRecipes(
+    var userId: Long,
+    var onLineRecipesId: String, //网络菜谱id
+    @PrimaryKey(autoGenerate = true)
+    var id: Long = 0,
+) {
+}

+ 16 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/db/entity/UserTag.kt

@@ -0,0 +1,16 @@
+package com.develop.common.data_repo.db.entity
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.serialization.Serializable
+
+@Serializable
+@Entity(tableName = "user_tag")
+data class UserTag(
+    var userId: Long,
+    @PrimaryKey
+    var recipesId: String,
+    var starCount: Int = 0,
+    var daily: String,
+) {
+}

+ 24 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/Api.kt

@@ -0,0 +1,24 @@
+package com.develop.common.data_repo.net
+
+/**
+ * 全局API接口
+ */
+object Api {
+    const val HOST = "http://nat.kuyuntech.com:19973/dev/"
+
+    const val REGISTER = "register"
+    const val LOGIN = "login"
+    const val PERFECT_INFO = "perfetInfo"
+    const val SEND_VERIFY_CODE = "sendVerifyCode"
+    const val UPDATE_PWD = "updatePassword"
+    const val SCORE = "score"
+    const val GET_RECIPES = "recipes"
+    const val GET_RECIPES_DETAIL = "recipeDetail"
+    const val GET_CATEGORIES = "categorys"
+    const val ACTIVE = "active"
+    const val DEV_INFO = "devInfo"
+    const val GET_NOTICES = "notices"
+    const val GET_HOT_TAGS = "hotTags"
+
+
+}

+ 80 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/converter/SerializationConverter.kt

@@ -0,0 +1,80 @@
+@file:Suppress("UNCHECKED_CAST", "MemberVisibilityCanBePrivate")
+
+package com.develop.common.data_repo.net.converter
+
+import com.drake.net.NetConfig
+import com.drake.net.convert.NetConverter
+import com.drake.net.exception.ConvertException
+import com.drake.net.exception.RequestParamsException
+import com.drake.net.exception.ResponseException
+import com.drake.net.exception.ServerResponseException
+import com.drake.net.request.kType
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.serializer
+import okhttp3.Response
+import org.json.JSONException
+import org.json.JSONObject
+import java.lang.reflect.Type
+import kotlin.reflect.KType
+
+/**
+ * 自定义的序列化
+ * 传入参数根据实际需求修改
+ */
+class SerializationConverter(
+    val success: Int = 200,
+    val code: String = "status",
+    val message: String = "desc",
+) : NetConverter {
+
+    companion object {
+        val jsonDecoder = Json {
+            ignoreUnknownKeys = true // JSON和数据模型字段可以不匹配
+            coerceInputValues = true // 如果JSON字段是Null则使用默认值
+        }
+    }
+
+    override fun <R> onConvert(succeed: Type, response: Response): R? {
+        try {
+            return NetConverter.onConvert<R>(succeed, response)
+        } catch (e: ConvertException) {
+            val code = response.code
+            when {
+                code in 200..299 -> { // 请求成功
+                    val bodyString = response.body?.string() ?: return null
+                    val kType = response.request.kType
+                        ?: throw ConvertException(response, "Request does not contain KType")
+                    return try {
+                        val json = JSONObject(bodyString) // 获取JSON中后端定义的错误码和错误信息
+                        val srvCode = json.getInt(this.code)
+                        if (srvCode == success) { // 对比后端自定义错误码
+                            json.getString("data").parseBody<R>(kType)
+                        } else { // 错误码匹配失败, 开始写入错误异常
+                            val errorMessage = json.optString(
+                                message,
+                                NetConfig.app.getString(com.drake.net.R.string.no_error_message)
+                            )
+                            throw ResponseException(
+                                response,
+                                errorMessage,
+                                tag = srvCode
+                            ) // 将业务错误码作为tag传递
+                        }
+                    } catch (e: JSONException) { // 固定格式JSON分析失败直接解析JSON
+                        bodyString.parseBody<R>(kType)
+                    }
+                }
+                code in 400..499 -> throw RequestParamsException(
+                    response,
+                    code.toString()
+                ) // 请求参数错误
+                code >= 500 -> throw ServerResponseException(response, code.toString()) // 服务器异常错误
+                else -> throw ConvertException(response)
+            }
+        }
+    }
+
+    fun <R> String.parseBody(succeed: KType): R? {
+        return jsonDecoder.decodeFromString(Json.serializersModule.serializer(succeed), this) as R
+    }
+}

+ 20 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/interceptor/FoodRequestInterceptor.kt

@@ -0,0 +1,20 @@
+package com.develop.common.data_repo.net.interceptor
+
+import com.blankj.utilcode.util.AppUtils
+import com.develop.base.ext.getSN
+import com.drake.net.interceptor.RequestInterceptor
+import com.drake.net.request.BaseRequest
+
+/** 请求拦截器, 一般用于添加全局参数 */
+class FoodRequestInterceptor : RequestInterceptor {
+
+    /** 本方法每次请求发起都会调用, 这里添加的参数可以是动态参数 */
+    override fun interceptor(request: BaseRequest) {
+        request.apply {
+            addHeader("sn", getSN())
+            addHeader("apkVersion", AppUtils.getAppVersionName())
+            addHeader("mcuVersion", "1.0")
+            addHeader("Connection","close")
+        }
+    }
+}

+ 17 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/ActivateBody.kt

@@ -0,0 +1,17 @@
+package com.develop.common.data_repo.net.model.request
+
+import com.blankj.utilcode.util.AppUtils
+import com.develop.base.ext.genMultipartBody
+import com.develop.base.ext.getSN
+import okhttp3.RequestBody
+
+object ActivateBody {
+    fun genActivateBody(
+    ): RequestBody {
+        val map = HashMap<String, String>()
+        map["apkVersin"] = AppUtils.getAppVersionName()
+        map["mcuVersion"] = ""
+        map["sn"] = getSN()
+        return map.genMultipartBody()
+    }
+}

+ 20 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/DeviceInfoBody.kt

@@ -0,0 +1,20 @@
+package com.develop.common.data_repo.net.model.request
+
+import com.blankj.utilcode.util.AppUtils
+import com.develop.base.ext.genMultipartBody
+import com.develop.base.ext.getSN
+import com.develop.common.data_repo.FoodDataProvider
+import okhttp3.RequestBody
+
+object DeviceInfoBody {
+    fun genDeviceInfoBody(
+    ): RequestBody {
+        val v = FoodDataProvider.getUserDatabase().devConfigDao().recipeVersion()
+        val recipeUpdateTime: Long = v.recipeUpdateTime ?: 0
+        val map = HashMap<String, String>()
+        map["apkVersin"] = AppUtils.getAppVersionName()
+        map["sn"] = getSN()
+        map["recipeUpdateTime"] = recipeUpdateTime.toString()
+        return map.genMultipartBody()
+    }
+}

+ 16 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/LoginBody.kt

@@ -0,0 +1,16 @@
+package com.develop.common.data_repo.net.model.request
+
+import com.develop.base.ext.genMultipartBody
+import com.develop.base.ext.getSN
+import okhttp3.RequestBody
+
+
+object LoginBody {
+    fun genLoginBody(account: String, password: String): RequestBody {
+        val map = HashMap<String, String>()
+        map["account"] = account
+        map["password"] = password
+        map["sn"] = getSN()
+        return map.genMultipartBody()
+    }
+}

+ 21 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/PerfectInfoBody.kt

@@ -0,0 +1,21 @@
+package com.develop.common.data_repo.net.model.request
+
+
+import com.develop.base.ext.genMultipartBody
+import okhttp3.RequestBody
+
+object PerfectInfoBody {
+    fun genPerfectInfoBody(
+        nickname: String,
+        gender: String,
+        portrait: String,
+        age: String
+    ): RequestBody {
+        val map = HashMap<String, String>()
+        map["nickname"] = nickname
+        map["gender"] = gender
+        map["portrait"] = portrait
+        map["age"] = age
+        return map.genMultipartBody()
+    }
+}

+ 16 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/RegisterBody.kt

@@ -0,0 +1,16 @@
+package com.develop.common.data_repo.net.model.request
+
+import com.develop.base.ext.genMultipartBody
+import com.develop.base.ext.getSN
+import okhttp3.RequestBody
+
+object RegisterBody {
+    fun genRegisterBody(account: String, password: String): RequestBody {
+        val map = HashMap<String, String>()
+        map["account"] = account
+        map["password"] = password
+        map["sn"] = getSN()
+        return map.genMultipartBody()
+    }
+
+}

+ 20 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/ScoreBody.kt

@@ -0,0 +1,20 @@
+package com.develop.common.data_repo.net.model.request
+
+import com.develop.base.ext.genMultipartBody
+import com.develop.base.ext.getSN
+import okhttp3.RequestBody
+
+object ScoreBody {
+    fun genScoreBody(
+        recipeNumber: String,
+        recipeEdition: String,
+        score: String,
+    ): RequestBody {
+        val map = HashMap<String, String>()
+        map["recipeNumber"] = recipeNumber
+        map["recipeEdition"] = recipeEdition
+        map["score"] = score
+        map["sn"] = getSN()
+        return map.genMultipartBody()
+    }
+}

+ 14 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/SendVerifyCodeBody.kt

@@ -0,0 +1,14 @@
+package com.develop.common.data_repo.net.model.request
+
+import com.develop.base.ext.genMultipartBody
+import com.develop.base.ext.getSN
+import okhttp3.RequestBody
+
+object SendVerifyCodeBody {
+    fun genSendVerifyCodeBody(account: String): RequestBody {
+        val map = HashMap<String, String>()
+        map["account"] = account
+        map["sn"] = getSN()
+        return map.genMultipartBody()
+    }
+}

+ 22 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/request/UpdatePasswordBody.kt

@@ -0,0 +1,22 @@
+package com.develop.common.data_repo.net.model.request
+
+import com.develop.base.ext.genMultipartBody
+import com.develop.base.ext.getSN
+import okhttp3.RequestBody
+
+object UpdatePasswordBody {
+    fun genUpdatePasswordBody(
+        account: String,
+        password: String,
+        verifyCodeKey: String,
+        verifyCode: String
+    ): RequestBody {
+        val map = HashMap<String, String>()
+        map["account"] = account
+        map["sn"] = getSN()
+        map["password"] = password
+        map["verifyCodeKey"] = verifyCodeKey
+        map["verifyCode"] = verifyCode
+        return map.genMultipartBody()
+    }
+}

+ 9 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/CategoryListResult.kt

@@ -0,0 +1,9 @@
+package com.develop.common.data_repo.net.model.response
+
+import com.develop.common.data_repo.db.entity.DevRecipeCategory
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class CategoryListResult(
+    val categorys: List<DevRecipeCategory>
+)

+ 79 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/DevInfoResult.kt

@@ -0,0 +1,79 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class DevInfoResult(
+    val apkInfo: ApkInfo,
+    val apkUpdate: Boolean,
+    val apkUrl: String,
+    val newRecipes: List<String>,
+    val lockScreenAdss: List<LockScreenAds>,
+    val recipeUpdateTime:Long
+)
+
+@Serializable
+data class ApkInfo(
+    val apk: String,
+    val apkCode: String,
+    val apkEdition: String,
+    val applyTime: Long,
+    val attachmentList: String,
+    val brandOwnerCity: String,
+    val brandOwnerCode: String,
+    val brandOwnerCountry: String,
+    val brandOwnerCountryLabel: String,
+    val brandOwnerCountryName: String,
+    val brandOwnerName: String,
+    val brandOwnerNumber: String,
+    val brandOwnerProvince: String,
+    val brandProductCode: String,
+    val code: String,
+    val createTime: Long,
+    val endTime: String,
+    val fileCode: String,
+    val fileSize: Int,
+    val id: Int,
+    val ignoreCode: String,
+    val installCount: String,
+    val materialFileCode: String,
+    val productCode: String,
+    val productModel: String,
+    val productName: String,
+    val productSubModel: String,
+    val releaseStatus: String,
+    val releaseTime: String,
+    val rollbackReason: String,
+    val rollbackTime: String,
+    val startTime: String,
+    val status: String,
+    val subApkSize: String,
+    val subBrandCode: String,
+    val subBrandName: String,
+    val subBrandNumber: String,
+    val subBrandProductCode: String,
+    val subEdition: String,
+    val testStatus: String,
+    val testTime: String,
+    val updateTime: Long,
+    val valid: Int,
+    val version: Int
+)
+@Serializable
+data class LockScreenAds(
+    val brandOwnerCode: String,
+    val brandOwnerNumber: String,
+    val code: String,
+    val createTime: Long,
+    val id: Int,
+    val ignoreCode: String,
+    val number: String,
+    val photo: String,
+    val productSubModel: String,
+    val subBrandCode: String,
+    val subBrandNumber: String,
+    val subBrandProductCode: String,
+    val updateTime: Long,
+    val valid: Int,
+    val version: Int
+)

+ 8 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/HotTagsResult.kt

@@ -0,0 +1,8 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class HotTagsResult(
+    val hotTags: List<String>
+)

+ 9 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/LoginResult.kt

@@ -0,0 +1,9 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class LoginResult(
+    val token: String,
+    val user: User
+)

+ 27 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/NoticeResult.kt

@@ -0,0 +1,27 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class NoticeResult(
+    val userInformRecords: List<UserInformRecord>
+)
+@Serializable
+data class UserInformRecord(
+    val brandOwnerCode: String,
+    val brandOwnerNumber: String,
+    val code: String,
+    val createTime: Long,
+    val deviceCode: String,
+    val id: Int,
+    val informCode: String,
+    val informNumber: String,
+    val readStatus: Boolean,
+    val readTime: String,
+    val sn: String,
+    val updateTime: Long,
+    val userCode: String,
+    val userNumber: String,
+    val valid: Int,
+    val version: Int
+)

+ 8 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/PerfectInfoResult.kt

@@ -0,0 +1,8 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class PerfectInfoResult(
+    val user: User
+)

+ 71 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/RecipeDetailResult.kt

@@ -0,0 +1,71 @@
+package com.develop.common.data_repo.net.model.response
+
+import com.develop.common.data_repo.db.entity.*
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class RecipeDetailResult(
+    val devAccessorys: List<DevAccessory>,
+    val devRecipe: DevRecipe,
+    val devRecipeFoods: List<DevRecipeFood>,
+    val devRecipeNutritions: List<DevRecipeNutrition>,
+    val devRecipePortionSizes: List<DevRecipePortionSize>,
+    val recipeAccessorys: List<DevRecipeAccessory>,
+    val recipeUrl: String
+)
+@Serializable
+data class RecipeDataConfig(
+    val devAccessorys: List<DevAccessory>,
+    val devHotTags: List<DevHotTag>,
+    val devPortraits: List<DevPortrait>,
+    val devRecipeAccessorys: List<DevRecipeAccessory>,
+    val devRecipeCategorys: List<DevRecipeCategory>,
+    val devRecipeCookingSteps: List<DevRecipeCookingStep>,
+    val devRecipeFoods: List<DevRecipeFood>,
+    val devRecipeNutritions: List<DevRecipeNutrition>,
+    val devRecipePortionSizes: List<DevRecipePortionSize>,
+    val devRecipeRelTags: List<DevRecipeRelTag>,
+    val devRecipeTags: List<DevRecipeTag>,
+    val devRecipes: List<DevRecipe>,
+) {
+
+
+    fun resetAllCodes() {
+        for (data in devAccessorys) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devHotTags) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devPortraits) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipeAccessorys) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipeCategorys) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipeCookingSteps) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipeFoods) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipeNutritions) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipePortionSizes) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipeRelTags) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipeTags) {
+            data.code = System.nanoTime().toString()
+        }
+        for (data in devRecipes) {
+            data.code = System.nanoTime().toString()
+        }
+    }
+}

+ 24 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/RecipesListResult.kt

@@ -0,0 +1,24 @@
+package com.develop.common.data_repo.net.model.response
+
+import com.develop.common.data_repo.db.entity.DevRecipe
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class RecipesListResult(
+    val pager: Pager,
+    val recipes: List<DevRecipe>
+)
+@Serializable
+data class Pager(
+    val beginIndex: Int,
+    val btnList: List<Int>,
+    val btnNum: Int,
+    val first: Boolean,
+    val itemCount: Int,
+    val items: List<DevRecipe>,
+    val last: Boolean,
+    val onPage: Boolean,
+    val pageCount: Int,
+    val pageIndex: Int,
+    val pageSize: Int
+)

+ 38 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/RegisterResult.kt

@@ -0,0 +1,38 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class RegisterResult(
+    val user: User
+)
+@Serializable
+data class User(
+    val account: String,
+    val age: Int,
+    val areaName: String,
+    val brandOwnerCode: String,
+    val brandOwnerNumber: String,
+    val city: String,
+    val cityName: String,
+    val code: String,
+    val country: String,
+    val countryName: String,
+    val createTime: Long,
+    val endTime: String,
+    val gender: String?,
+    val id: Int,
+    val makeCount: String,
+    val nickname: String,
+    val number: String,
+    val password: String,
+    val portrait: String?,
+    val province: String,
+    val provinceName: String,
+    val registerTime: String,
+    val startTime: String,
+    val status: String,
+    val updateTime: Long,
+    val valid: Int,
+    val version: Int
+)

+ 36 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/ScoreResult.kt

@@ -0,0 +1,36 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class ScoreResult(
+    val recipeUserEvaluation: RecipeUserEvaluation
+)
+
+@Serializable
+data class RecipeUserEvaluation(
+    val brandOwnerCode: String,
+    val brandOwnerNumber: String,
+    val code: String,
+    val content: String,
+    val createTime: Long,
+    val endTime: String,
+    val evaluationTime: Long,
+    val id: Int,
+    val recipeCategoryCode: String,
+    val recipeCategoryName: String,
+    val recipeCategoryNumber: String,
+    val recipeCode: String,
+    val recipeEdition: String,
+    val recipeEditionCode: String,
+    val recipeName: String,
+    val recipeNumber: String,
+    val score: Int,
+    val startTime: String,
+    val updateTime: Long,
+    val userAccount: String,
+    val userCode: String,
+    val userNumber: String,
+    val valid: Int,
+    val version: Int
+)

+ 7 - 0
BusinessCommon/src/main/java/com/develop/common/data_repo/net/model/response/VerifyCodeResult.kt

@@ -0,0 +1,7 @@
+package com.develop.common.data_repo.net.model.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class VerifyCodeResult(var verifyCodeKey: String) {
+}

+ 44 - 0
BusinessCommon/src/main/java/com/develop/common/dialog/AgeSelectDialog.kt

@@ -0,0 +1,44 @@
+package com.develop.common.dialog
+
+import android.graphics.Color
+import androidx.appcompat.app.AppCompatActivity
+import com.develop.common.R
+import com.develop.common.databinding.DialogDataPickerBinding
+import com.google.android.material.bottomsheet.BottomSheetDialog
+
+class AgeSelectDialog(
+    private val activity: AppCompatActivity,
+    private val onConfirm: (index: Int, change: Boolean) -> Unit
+): BottomSheetDialog(activity, R.style.BottomSheetDialog) {
+
+    private val binding = DialogDataPickerBinding.inflate(activity.layoutInflater)
+    private val initIndex = 0
+    init {
+        val listData = createAgeListData()
+        setContentView(binding.root)
+        binding.tvCancel.setOnClickListener {
+            dismiss()
+        }
+        binding.tvConfirm.setOnClickListener {
+            dismiss()
+            val currentIndex = binding.wheelPicker.currentItemPosition
+            onConfirm(currentIndex, true)
+        }
+        binding.wheelPicker.selectedItemTextColor = Color.BLACK
+        binding.wheelPicker.itemTextColor = 0xff000000.toInt()
+        binding.wheelPicker.setAtmospheric(true)
+        binding.wheelPicker.isCurved = true
+        binding.wheelPicker.data = listData
+        if (initIndex >= 0 && initIndex <= listData.size - 1) {
+            binding.wheelPicker.setSelectedItemPosition(initIndex, false)
+        }
+    }
+
+    private fun createAgeListData(): List<String> {
+        val list = mutableListOf<String>()
+        for (index in 20..80) {
+            list.add(index.toString())
+        }
+        return list
+    }
+}

+ 72 - 0
BusinessCommon/src/main/java/com/develop/common/dialog/CancelConfirmDialog.kt

@@ -0,0 +1,72 @@
+package com.develop.common.dialog
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RelativeLayout
+import com.develop.base.mvvm.FullScreenTransparentDialog
+import com.develop.common.databinding.DialogCancelConfirmBinding
+
+
+class CancelConfirmDialog(
+) : FullScreenTransparentDialog() {
+
+    lateinit var binding: DialogCancelConfirmBinding
+
+    var title = ""
+    var cancelStr = ""
+    var confirmStr = ""
+    var showConfirm = true
+    var showCancel = true
+    var onDialogClickListener: OnDialogClickListener? = null
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+    ): View {
+        binding = DialogCancelConfirmBinding.inflate(
+            inflater, container, false
+        )
+        binding.tvYes.setOnClickListener {
+            onDialogClickListener?.onConfirm()
+            removeSelf()
+        }
+        binding.tvCancel.setOnClickListener {
+            onDialogClickListener?.onCancel()
+            removeSelf()
+        }
+        binding.tvTitle.text = title
+        if (cancelStr.isNotEmpty()) {
+            binding.tvCancel.text = cancelStr
+        }
+        if (confirmStr.isNotEmpty()) {
+            binding.tvYes.text = confirmStr
+        }
+
+        //只显示确认按钮
+        if (showConfirm && !showCancel) {
+            binding.tvCancel.visibility = View.GONE;
+            binding.tvYes.visibility = View.VISIBLE;
+            val layoutParams = binding.tvYes.layoutParams as RelativeLayout.LayoutParams;
+            layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL)
+            binding.tvCancel.layoutParams = layoutParams
+        }
+
+        if (!showConfirm && showCancel) {
+            binding.tvYes.visibility = View.GONE;
+            binding.tvCancel.visibility = View.VISIBLE;
+            val layoutParams = binding.tvCancel.layoutParams as RelativeLayout.LayoutParams;
+            layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL)
+            binding.tvCancel.layoutParams = layoutParams
+        }
+
+
+
+        return binding.root
+    }
+
+
+    interface OnDialogClickListener {
+        fun onConfirm()
+        fun onCancel()
+    }
+}

+ 43 - 0
BusinessCommon/src/main/java/com/develop/common/dialog/CommonDialog.kt

@@ -0,0 +1,43 @@
+package com.develop.common.dialog
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.develop.base.mvvm.FullScreenTransparentDialog
+import com.develop.common.databinding.DialogCommonBinding
+
+
+class CommonDialog(
+) : FullScreenTransparentDialog() {
+    private lateinit var binding: DialogCommonBinding
+
+    var msg = ""
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        binding = DialogCommonBinding.inflate(
+            inflater, container, false
+        )
+        binding.tvMsg.text = msg
+        binding.tvOk.setOnClickListener {
+            removeSelf()
+        }
+        if (!hasOKBtn) {
+            binding.tvOk.visibility = View.INVISIBLE
+            binding.tvProgress.visibility = View.VISIBLE
+        } else {
+            binding.tvOk.visibility = View.VISIBLE
+            binding.tvProgress.visibility = View.GONE
+        }
+        return binding.root
+    }
+
+    var hasOKBtn: Boolean = true
+
+    fun updateProgress(progress: String) {
+        binding.tvProgress.text = progress
+    }
+}

+ 39 - 0
BusinessCommon/src/main/java/com/develop/common/dialog/GenderSelectDialog.kt

@@ -0,0 +1,39 @@
+package com.develop.common.dialog
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.develop.base.mvvm.FullScreenTransparentDialog
+import com.develop.common.databinding.DialogGenderSelectBinding
+
+
+class GenderSelectDialog(
+    private val onSelect: (male: Boolean) -> Unit
+) : FullScreenTransparentDialog() {
+
+    private lateinit var binding: DialogGenderSelectBinding
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        binding = DialogGenderSelectBinding.inflate(
+            inflater, container, false
+        )
+        binding.tvSelectMale.setOnClickListener {
+            binding.tvSelectFemale.isSelected = false
+            binding.tvSelectMale.isSelected = true
+            onSelect(true)
+            removeSelf()
+        }
+        binding.tvSelectFemale.setOnClickListener {
+            binding.tvSelectFemale.isSelected = true
+            binding.tvSelectMale.isSelected = false
+            onSelect(false)
+            removeSelf()
+        }
+        return binding.root
+    }
+}

+ 28 - 0
BusinessCommon/src/main/java/com/develop/common/dialog/LoadingDialog.kt

@@ -0,0 +1,28 @@
+package com.develop.common.dialog
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.develop.base.ext.updateText
+import com.develop.base.mvvm.FullScreenTransparentDialog
+import com.develop.common.databinding.DialogLoadingBinding
+
+class LoadingDialog : FullScreenTransparentDialog() {
+
+    var loadingTitle = "Loading"
+    private lateinit var binding:DialogLoadingBinding
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        binding = DialogLoadingBinding.inflate(inflater,container,false)
+        return binding.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        binding.tvLoading.updateText(loadingTitle)
+    }
+}

+ 84 - 0
BusinessCommon/src/main/java/com/develop/common/dialog/PlainDialogView.java

@@ -0,0 +1,84 @@
+package com.develop.common.dialog;
+
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import androidx.activity.ComponentActivity;
+import androidx.activity.OnBackPressedCallback;
+import androidx.annotation.UiThread;
+
+public class PlainDialogView {
+    private final ComponentActivity activity;
+    private final int layoutId;
+    private View dialogRoot;
+    private View dialogView;
+    private boolean dialogShow;
+    private boolean cancelable;
+    private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
+        @Override
+        public void handleOnBackPressed() {
+            if (cancelable) {
+                hideDialog();
+            }
+        }
+    };
+
+    public PlainDialogView(ComponentActivity activity, int layoutId) {
+        this.activity = activity;
+        this.layoutId = layoutId;
+        activity.getOnBackPressedDispatcher().addCallback(onBackPressedCallback);
+    }
+
+    public void showDialog() {
+        showDialog(false);
+    }
+
+    @UiThread
+    public void showDialog(boolean cancelable) {
+        this.dialogShow = true;
+        this.cancelable = cancelable;
+        if (dialogRoot == null) {
+            dialogRoot = new FrameLayout(activity);
+            dialogRoot.setClickable(true);
+            dialogRoot.setBackgroundColor(Color.parseColor("#AA000000"));
+            dialogRoot.setLayoutParams(new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.MATCH_PARENT,
+                FrameLayout.LayoutParams.MATCH_PARENT
+            ));
+        }
+        if (dialogView == null) {
+            dialogView = View.inflate(activity, layoutId, (ViewGroup) dialogRoot);
+        }
+        detachRootView();
+        dialogRoot.setAlpha(0f);
+        FrameLayout container = (FrameLayout) activity.getWindow().getDecorView();
+        container.addView(dialogRoot, new FrameLayout.LayoutParams(
+            FrameLayout.LayoutParams.MATCH_PARENT,
+            FrameLayout.LayoutParams.MATCH_PARENT
+        ));
+        dialogRoot.animate().alpha(1f).setDuration(300).start();
+        onBackPressedCallback.setEnabled(true);
+    }
+
+    @UiThread
+    public void hideDialog() {
+        onBackPressedCallback.setEnabled(false);
+        if (dialogView == null) {
+            return;
+        }
+        if (dialogRoot.getParent() == null || !dialogShow) {
+            return;
+        }
+        dialogShow = false;
+        dialogRoot.animate().alpha(0f).setDuration(200).withEndAction(this::detachRootView);
+    }
+
+    private void detachRootView() {
+        ViewGroup parent = (ViewGroup) dialogRoot.getParent();
+        if (parent != null) {
+            parent.removeView(dialogRoot);
+        }
+    }
+}

+ 145 - 0
BusinessCommon/src/main/java/com/develop/common/dialog/RecipeUpdateDialog.kt

@@ -0,0 +1,145 @@
+package com.develop.common.dialog
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RelativeLayout
+import androidx.fragment.app.FragmentManager
+import com.develop.base.mvvm.FullScreenTransparentDialog
+import com.develop.base.util.ThreadUtils
+import com.develop.base.util.TopResumedAtyHolder
+import com.develop.common.R
+import com.develop.common.databinding.DialogRecipeUpdateBinding
+
+class RecipeUpdateDialog() : FullScreenTransparentDialog() {
+
+    lateinit var binding: DialogRecipeUpdateBinding
+
+    lateinit var onDialogClickListener: OnDialogClickListener
+
+    var type = "UPDATE_TIPS";
+
+    var msg = ""
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+    ): View {
+        binding = DialogRecipeUpdateBinding.inflate(
+            inflater, container, false
+        )
+
+        binding.tvYes.setOnClickListener {
+            onDialogClickListener.onConfirm()
+            removeSelf()
+        }
+
+        binding.tvCancel.setOnClickListener {
+            onDialogClickListener.onCancel()
+            removeSelf()
+        }
+
+        if (type == "UPDATE_TIPS") {
+            binding.tvMsg.text = msg
+            binding.tvCancel.visibility = View.VISIBLE;
+            binding.tvYes.visibility = View.VISIBLE;
+        }
+
+        if (type == "NO_UPDATE") {
+            binding.tvMsg.text = msg
+
+            binding.tvCancel.visibility = View.GONE;
+            binding.tvYes.visibility = View.VISIBLE;
+            val layoutParams = binding.tvYes.layoutParams as RelativeLayout.LayoutParams;
+            layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL)
+            binding.tvCancel.layoutParams = layoutParams
+            binding.tvYes.text = getString(R.string.ok)
+        }
+
+        if (type == "UPDATING") {
+            binding.tvMsg.text = msg
+            binding.tvCancel.visibility = View.GONE;
+            binding.tvYes.visibility = View.VISIBLE;
+            binding.loading.visibility = View.VISIBLE;
+            binding.success.visibility = View.GONE;
+            val layoutParams = binding.tvYes.layoutParams as RelativeLayout.LayoutParams;
+            layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL)
+            binding.tvCancel.layoutParams = layoutParams
+            binding.tvYes.text = getString(R.string.stop)
+        }
+
+        if (type == "SUCCESS") {
+            binding.tvMsg.text = msg
+            binding.tvCancel.visibility = View.GONE;
+            binding.tvYes.visibility = View.VISIBLE;
+            binding.loading.visibility = View.GONE;
+            binding.success.visibility = View.VISIBLE;
+            val layoutParams = binding.tvYes.layoutParams as RelativeLayout.LayoutParams;
+            layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL)
+            binding.tvCancel.layoutParams = layoutParams
+            binding.tvYes.text = getString(R.string.ok)
+        }
+
+        return binding.root
+    }
+
+    fun showNoUpdateTips(manager: FragmentManager, tag: String) {
+        TopResumedAtyHolder.getCurrentActivity()?.apply {
+            msg = getString(R.string.no_recipe_update_tips)
+        }
+        type = "NO_UPDATE"
+        show(manager, tag)
+    }
+
+    fun showUpdating(
+        manager: FragmentManager, tag: String, current: Long, total: Long
+    ) {
+
+        TopResumedAtyHolder.getCurrentActivity()?.apply {
+            msg = getString(R.string.recipe_update_process_tips).replace(
+                "{{progress}}",
+                "${current}/${total}"
+            )
+        }
+        if (isAdded) {
+            ThreadUtils.runOnMainThread {
+                dialog?.hide()
+                binding.tvMsg.text = msg
+                dialog?.show()
+            }
+        } else {
+            type = "UPDATING"
+            show(manager, tag)
+        }
+
+
+    }
+
+    fun showSuccess(
+        manager: FragmentManager, tag: String
+    ) {
+        TopResumedAtyHolder.getCurrentActivity()?.apply {
+            msg = getString(R.string.recipe_update_finish)
+
+        }
+        type = "SUCCESS"
+        show(manager, tag)
+    }
+
+    fun showUpdateTips(
+        manager: FragmentManager, tag: String, num: Long
+    ) {
+        TopResumedAtyHolder.getCurrentActivity()?.apply {
+            msg = getString(R.string.recipe_update_tips).replace("{{num}}", num.toString())
+        }
+        type = "UPDATE_TIPS"
+        show(manager, tag)
+    }
+
+
+    interface OnDialogClickListener {
+        fun onConfirm()
+        fun onCancel()
+    }
+
+}

+ 15 - 0
BusinessCommon/src/main/java/com/develop/common/event/CommonEvent.kt

@@ -0,0 +1,15 @@
+package com.develop.common.event
+
+
+class FinishAtyEvent() {
+}
+class RefreshDataEvent {}
+
+data class CookStepEvent(
+    var recipeNumber: String = "",
+    var coverPath: Any,
+    var step: Int = 0,
+    var isMode: Boolean = false,
+    var modeName: String = ""
+) {
+}

+ 182 - 0
BusinessCommon/src/main/java/com/develop/common/food_sdk/FloatWindowManager.kt

@@ -0,0 +1,182 @@
+package com.develop.common.food_sdk
+
+import android.annotation.SuppressLint
+import android.widget.ImageView
+import android.widget.RelativeLayout
+import androidx.appcompat.widget.AppCompatTextView
+import coil.load
+import com.blankj.utilcode.util.ScreenUtils.getScreenHeight
+import com.blankj.utilcode.util.ScreenUtils.getScreenWidth
+import com.develop.base.ext.globalApp
+import com.develop.base.ext.navigateTo
+import com.develop.base.ext.resId2Dimension
+import com.develop.base.util.ThreadUtils
+import com.develop.common.R
+import com.develop.common.dialog.CancelConfirmDialog
+import com.develop.common.event.CookStepEvent
+import com.develop.common.router.Screens
+import com.develop.common.tag.MODE_TYPE
+import com.kuyuntech.cofarcooking.device.sdk.constant.core.DevStatus
+import com.kuyuntech.cofarcooking.device.sdk.eventbus.event.DevStatusEvent
+import com.lzf.easyfloat.EasyFloat
+import com.lzf.easyfloat.enums.ShowPattern
+import com.lzf.easyfloat.enums.SidePattern
+import org.apache.commons.lang3.StringUtils
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+
+@SuppressLint("StaticFieldLeak")
+object FloatWindowManager {
+    private var filterClass: Array<Class<*>>
+    private var recipeNumber = ""
+    private var step = 0
+    private var coverPath: Any? = null
+    private var modeName = ""
+    private var isMode = false
+
+    private var ivFood: ImageView? = null
+    private var tvStep: AppCompatTextView? = null
+
+    private val confirmCancelDialog by lazy {
+        CancelConfirmDialog()
+    }
+
+    init {
+        filterClass = arrayOf(
+            getFilterClass(FilterClass.COOK_MODES),
+            getFilterClass(FilterClass.COOK_STEP),
+        )
+        EventBus.getDefault().register(this)
+
+        confirmCancelDialog.onDialogClickListener =
+            object : CancelConfirmDialog.OnDialogClickListener {
+                override fun onConfirm() {
+                    //确认
+
+                }
+
+                override fun onCancel() {
+                    //取消
+                }
+
+            }
+    }
+
+    fun showStepFlowWindow(event: CookStepEvent) {
+        recipeNumber = event.recipeNumber
+        coverPath = event.coverPath
+        step = event.step
+        modeName = event.modeName
+        isMode = event.isMode
+        if (!EventBus.getDefault().isRegistered(this)) {
+            EventBus.getDefault().register(this)
+        }
+        EasyFloat.with(globalApp())
+            .setShowPattern(ShowPattern.ALL_TIME)
+            .setFilter(*filterClass)
+            .setLayout(R.layout.step_float_window) {
+                ivFood = it.findViewById(R.id.iv_food)
+                tvStep = it.findViewById(R.id.tv_step_count)
+                ivFood?.load(coverPath)
+                if (isMode) {
+                    //当前是模式
+                    tvStep?.text = modeName
+                } else {
+                    //当前是菜谱
+                    tvStep?.text = "Step ${step + 1}"
+                }
+                it.findViewById<RelativeLayout>(R.id.content_layout).setOnClickListener {
+                    if (isMode) {
+                        globalApp().navigateTo(Screens.Cook.COOK_MODES) {
+                            withString(MODE_TYPE, modeName)
+                        }
+                    } else {
+                        globalApp().navigateTo(Screens.Cook.COOK_STEP2) {
+                            withString("number", recipeNumber)
+                            withInt("stepIndex", step)
+                        }
+                    }
+                }
+            }
+            .setSidePattern(SidePattern.RESULT_SIDE)
+            .setImmersionStatusBar(true)
+            .setLocation(
+                getScreenWidth() - com.develop.base.R.dimen.convert_420px.resId2Dimension().toInt(),
+                getScreenHeight() - com.develop.base.R.dimen.convert_206px.resId2Dimension().toInt()
+
+            )
+            .show()
+    }
+
+    fun hideStepFlowWindow() {
+        EventBus.getDefault().unregister(this)
+        if (EasyFloat.isShow()) {
+            EasyFloat.dismiss()
+        }
+    }
+
+    @Subscribe
+    fun onDevStateEvent(event: DevStatusEvent) {
+        event.devInfo?.apply {
+            ThreadUtils.runOnMainThread {
+                if (runningRecipeId?.isNotEmpty() == true) {
+                    recipeNumber = runningRecipeId
+                }
+                if (!StringUtils.isNotEmpty(runningRecipeId)) {
+                    tvStep?.text = modeName
+                } else {
+                    step = if (runningRecipeExt == "") 0 else runningRecipeExt.toInt()
+                    tvStep?.text = "Step ${step + 1}"
+                }
+
+                if (status.toByte() == DevStatus.STOP) {
+                    hideStepFlowWindow()
+                }
+            }
+        }
+    }
+
+    @Subscribe
+    fun onCookStepEvent(event: CookStepEvent) {
+        recipeNumber = event.recipeNumber
+        coverPath = event.coverPath
+        step = event.step
+        isMode = event.isMode
+        modeName = event.modeName
+        ivFood?.load(coverPath)
+        if (isMode) {
+            tvStep?.text = modeName
+        } else {
+            tvStep?.text = "Step ${step + 1}"
+        }
+    }
+
+//    @Subscribe
+//    fun onCookDevMsgEvent(event: DevPromptEvent) {
+//        TopResumedActivityHolder.getCurrentActivity()?.apply {
+//            confirmCancelDialog.title
+//            confirmCancelDialog.cancelStr = event.cancelBtnText
+//            confirmCancelDialog.confirmStr = event.cancelBtnText
+//            confirmCancelDialog.title = event.msg
+//            confirmCancelDialog.show(this.supportFragmentManager, "")
+//        }
+//    }
+
+
+    private fun getFilterClass(filterClass: FilterClass): Class<*> {
+        return when (filterClass) {
+            FilterClass.COOK_STEP -> {
+                Class.forName("com.develop.step.CookStepActivity2").newInstance()::class.java
+            }
+            else -> {
+                Class.forName("com.develop.step.modes.ModesDetailActivity")
+                    .newInstance()::class.java
+            }
+        }
+    }
+
+    enum class FilterClass {
+        COOK_STEP,
+        COOK_MODES
+    }
+}

+ 21 - 0
BusinessCommon/src/main/java/com/develop/common/food_sdk/FoodSdkUtils.kt

@@ -0,0 +1,21 @@
+package com.develop.common.food_sdk
+
+import com.kuyuntech.cofarcooking.device.sdk.constant.core.DevStatus
+import com.kuyuntech.cofarcooking.device.sdk.util.core.CofarSDK
+
+object FoodSdkUtils {
+
+    fun isDevRunning(): Boolean {
+        return CofarSDK.devInfo().status != DevStatus.STOP.toInt()
+    }
+
+    fun parseTemp(temp: Short): Short {
+        return if (temp <= 37 && temp.toInt() != 0) {
+            37
+        } else {
+            CofarSDK.parseTemp(temp)
+        }
+    }
+
+
+}

+ 183 - 0
BusinessCommon/src/main/java/com/develop/common/food_sdk/GlobalDevEvent.kt

@@ -0,0 +1,183 @@
+package com.develop.common.food_sdk
+
+import android.content.Context.POWER_SERVICE
+import android.os.PowerManager
+import android.util.Log
+import android.view.WindowManager
+import androidx.fragment.app.FragmentManager
+import com.develop.base.ext.globalApp
+import com.develop.base.ext.toJson
+import com.develop.base.util.ThreadUtils
+import com.develop.base.util.TopResumedAtyHolder
+import com.develop.common.R
+import com.develop.common.dialog.CancelConfirmDialog
+import com.kuyuntech.cofarcooking.device.sdk.constant.core.DevStatus
+import com.kuyuntech.cofarcooking.device.sdk.eventbus.event.DevPromptEvent
+import com.kuyuntech.cofarcooking.device.sdk.eventbus.event.DevStatusEvent
+import com.kuyuntech.cofarcooking.device.sdk.util.core.CofarSDK
+
+/**
+ * 全局处理烹饪设备回调的事件
+ */
+object GlobalDevEvent {
+
+    var keepScreen = false
+
+    private val weightAlignDialog by lazy {
+        CancelConfirmDialog()
+    }
+
+    private val devMsgDialog by lazy {
+        CancelConfirmDialog()
+    }
+
+    /**处理设备合盖问题*/
+    fun globalCoverEvent(event: DevStatusEvent) {
+        val devInfo = event.devInfo;
+        val pm = globalApp().getSystemService(POWER_SERVICE) as PowerManager
+        if (devInfo.status == DevStatus.RUNNING.toInt() && !keepScreen) {
+            ThreadUtils.runOnMainThread {
+                TopResumedAtyHolder.getCurrentActivity()?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+                keepScreen = true
+            }
+        } else if (devInfo.status != DevStatus.RUNNING.toInt() && keepScreen) {
+            ThreadUtils.runOnMainThread {
+                TopResumedAtyHolder.getCurrentActivity()?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+                keepScreen = false
+            }
+        }
+//        if (!pm.isScreenOn) {
+//            //合盖
+//            if (devInfo.potCloverStatus.toInt() == 0) {
+//                CofarSDK.flashWhiteRedLed()
+//            } else {
+//                CofarSDK.switchWhiteLed('0');
+//                CofarSDK.flashRedLed()
+//            }
+//        } else {
+//            if (devInfo.status == DevStatus.STOP.toInt() || devInfo.status == DevStatus.RUNNING.toInt()) {
+//                if (devInfo.temp < 60) {
+//                    CofarSDK.switchRedLed('0');
+//                    CofarSDK.switchWhiteLed('1');
+//                } else {
+//                    CofarSDK.switchRedLed('1');
+//                    CofarSDK.switchWhiteLed('0');
+//                }
+//            }
+//            if (devInfo.status == DevStatus.PAUSE.toInt()) {
+//                //判断盖子是否打开
+//                //合盖
+//                if (devInfo.potCloverStatus.toInt() == 1) {
+//                    CofarSDK.switchWhiteLed('0');
+//                    CofarSDK.flashRedLed()
+//                } else {
+//                    if (devInfo.temp < 60) {
+//                        CofarSDK.switchRedLed('0');
+//                        CofarSDK.flashWhiteLed();
+//                    } else {
+//                        CofarSDK.flashRedLed();
+//                        CofarSDK.switchWhiteLed('0');
+//                    }
+//                }
+//
+//
+//            }
+//        }
+
+    }
+
+
+    /**处理设备称重问题*/
+    fun globalWeightEvent(event: DevStatusEvent) {
+        ThreadUtils.runOnMainThread {
+            Log.d("ddddddddd", event.devInfo.toJson())
+            TopResumedAtyHolder.getCurrentActivity()?.apply {
+                if (event.devInfo.weightAlignStatus == (0).toByte()) { //正在标定不是
+                    weightAlignDialog.removeSelf()
+                    weightAlignDialog.showCancel = false
+                    weightAlignDialog.confirmStr = getString(R.string.exit_weight_align)
+                    weightAlignDialog.title = getString(R.string.weight_aligning)
+                    if (event.devInfo.weightPol == (1).toByte()) {
+                        weightAlignDialog.binding.tvTitle.text =
+                            getString(R.string.weight_one_kg_tips)
+                    }
+
+                    if (event.devInfo.weightPol == (2).toByte()) {
+                        weightAlignDialog.binding.tvTitle.text =
+                            getString(R.string.weight_two_kg_tips)
+                    }
+                }
+
+                if (event.devInfo.weightAlignStatus == (2).toByte()) { //正在标定不是
+                    weightAlignDialog.removeSelf()
+                    CofarSDK.unregister(this)
+                    weightAlignDialog.showCancel = false
+                    weightAlignDialog.confirmStr = getString(R.string.exit_weight_align)
+                    weightAlignDialog.title = getString(R.string.weight_align_success)
+                }
+
+                weightAlignDialog.showDialog(supportFragmentManager, "weight_align_dialog")
+                weightAlignDialog.onDialogClickListener =
+                    object : CancelConfirmDialog.OnDialogClickListener {
+                        override fun onConfirm() {
+                            exitWeightAlign()
+                        }
+
+                        override fun onCancel() {
+                            exitWeightAlign()
+                        }
+
+                    }
+            }
+        }
+    }
+
+    /**处理设备提示弹窗*/
+    fun globalDevMsgEvent(event: DevPromptEvent, fragmentManager: FragmentManager) {
+        devMsgDialog.onDialogClickListener = object : CancelConfirmDialog.OnDialogClickListener {
+            override fun onConfirm() {
+                event.confirm?.callback()
+            }
+
+            override fun onCancel() {
+                event.confirm?.callback()
+            }
+
+        }
+        devMsgDialog.showDialog(fragmentManager, "devMsgDialog")
+        devMsgDialog.apply {
+            showCancel = event.isShowCancelBtn
+            showConfirm = event.isShowConfirmBtn
+            cancelStr = resources.getString(
+                resources.getIdentifier(
+                    event.cancelBtnText, "string", globalApp().packageName
+                )
+            )
+            confirmStr = resources.getString(
+                resources.getIdentifier(
+                    event.confirmButtonText, "string", globalApp().packageName
+                )
+            )
+            title = resources.getString(
+                resources.getIdentifier(
+                    event.msg, "string", globalApp().packageName
+                )
+            )
+        }
+
+    }
+
+
+    //退出称重校准
+    private fun exitWeightAlign() {
+        CofarSDK.stoptWeightAlign()
+        CofarSDK.unregister(this)
+    }
+
+
+    fun dismissDialog() {
+        weightAlignDialog.removeSelf()
+        devMsgDialog.removeSelf()
+    }
+
+}

+ 52 - 0
BusinessCommon/src/main/java/com/develop/common/food_sdk/ProtocolListener.kt

@@ -0,0 +1,52 @@
+package com.develop.common.food_sdk
+
+import android.serialport.SerialPort
+import android.util.Log
+import com.kuyuntech.cofarcooking.device.sdk.protocol.core.BaseDecoder
+import com.kuyuntech.cofarcooking.device.sdk.util.core.CofarSDK
+import java.util.*
+
+
+class ProtocolListener(private val serialPort: SerialPort) : Runnable {
+
+    override fun run() {
+        try {
+            var tmp = ByteArray(1024)
+            var len = -1
+            val bytes: MutableList<Byte> = ArrayList()
+            while (serialPort.inputStream.read(tmp).also { len = it } != -1) {
+                val cmdTmp = tmp.copyOf(len)
+                tmp = ByteArray(1024)
+                for (b in cmdTmp) {
+                    if (b.toInt() == 0x7e) {
+                        if (bytes.size == 0) {
+                            bytes.add(b)
+                        } else {
+                            bytes.add(b)
+                            try {
+                                val cmd = ByteArray(bytes.size)
+                                for (i in bytes.indices) {
+                                    cmd[i] = bytes[i]
+                                }
+                                val baseDecoder = BaseDecoder(cmd)
+                                Log.i("mcu2dev:", baseDecoder.escapeBytesStr())
+                                CofarSDK.post2Dev(baseDecoder.baseBody)
+                                bytes.clear()
+                            } catch (e: Exception) {
+                                e.printStackTrace()
+                                Log.i("weilai-protocol", e.message!!)
+                                bytes.clear()
+                                bytes.add(b)
+                            }
+                        }
+                    } else if (bytes.size != 0) {
+                        bytes.add(b)
+                    }
+                }
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+            Log.i("weilai-protocol", e.message!!)
+        }
+    }
+}

+ 53 - 0
BusinessCommon/src/main/java/com/develop/common/food_sdk/SerialPortUtils.kt

@@ -0,0 +1,53 @@
+package com.develop.common.food_sdk
+
+import android.serialport.SerialPort
+import android.util.Log
+import com.kuyuntech.cofarcooking.device.sdk.eventbus.event.Dev2McuDataEvent
+import com.kuyuntech.cofarcooking.device.sdk.eventbus.listener.Dev2McuEventListener
+import com.kuyuntech.cofarcooking.device.sdk.eventbus.listener.Mcu2DevEventListener
+import com.kuyuntech.cofarcooking.device.sdk.util.core.CofarSDK
+import com.kuyuntech.cofarcooking.device.sdk.util.core.Converter
+import java.io.File
+import java.io.IOException
+
+object SerialPortUtils {
+
+    private var thread: Thread? = null
+
+    fun init() {
+        val serialPortPath = "/dev/ttyS1"
+        val baudRate = 9600
+        val dataBits = 8
+        val parity = 0
+        val stopBits = 1
+        val flags = 0
+        try {
+            SerialPort.setSuPath("/system/xbin/su")
+            val serialPort =
+                SerialPort(File(serialPortPath), baudRate, dataBits, parity, stopBits, flags)
+            val dev2McuEventListener = Dev2McuEventListener { event: Dev2McuDataEvent ->
+                Log.i("dev2mcu:", event.data)
+                val data = Converter.hexStringToBytes(event.data)
+                try {
+                    serialPort.outputStream.write(data)
+                } catch (e: IOException) {
+                    e.printStackTrace()
+                }
+            }
+            CofarSDK.register(dev2McuEventListener)
+            CofarSDK.register(Mcu2DevEventListener())
+            val protocolListener = ProtocolListener(serialPort)
+            thread = Thread(protocolListener)
+            thread?.start()
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+    }
+
+    fun destroy() {
+        thread?.interrupt()
+        thread = null
+    }
+
+
+}

+ 45 - 0
BusinessCommon/src/main/java/com/develop/common/router/Screens.kt

@@ -0,0 +1,45 @@
+package com.develop.common.router
+
+/**
+ * 页面路由
+ */
+object Screens {
+
+    object Auth {
+        private const val SCHEMA = "/auth"
+        const val MEMBER = "$SCHEMA/member"
+    }
+
+    object Setting {
+        private const val SCHEMA = "/setting"
+        const val ANIMATION = "$SCHEMA/animation"
+        const val LANGUAGE = "$SCHEMA/language"
+        const val POLICY = "$SCHEMA/policy"
+        const val WIFI = "$SCHEMA/wifi"
+        const val SCREEN_SAVER = "$SCHEMA/screen_saver"
+        const val MAIN_SETTING = "$SCHEMA/main_setting"
+        const val BRIGHTNESS = "$SCHEMA/brightness"
+        const val SOUND = "$SCHEMA/sound"
+        const val ABOUT = "$SCHEMA/about"
+        const val RESTORE = "$SCHEMA/restore"
+    }
+
+    object Main {
+        private const val SCHEMA = "/main"
+        const val ENTRANCE_CHOSEN = "$SCHEMA/entrance_chosen"
+        const val HOME = "$SCHEMA/home"
+    }
+
+    object Cook {
+
+        private const val SCHEMA = "/cook"
+        const val FOOD_LIST = "$SCHEMA/food_list"
+        const val COOK_STEP = "$SCHEMA/cook_step"
+        const val COOK_MODES = "$SCHEMA/cook_modes"
+        const val COOK_DETAIL = "${SCHEMA}/cook_detail"
+
+        // todo temp
+        const val COOK_STEP2 = "$SCHEMA/cook_step2"
+        const val COOK_EVALUATE = "$SCHEMA/cook_evaluate"
+    }
+}

+ 44 - 0
BusinessCommon/src/main/java/com/develop/common/tag/CommonTag.kt

@@ -0,0 +1,44 @@
+package com.develop.common.tag
+
+import com.develop.base.util.MMkvUtils
+
+const val FIRST_IN = "FIRST_IN"
+
+const val FOOL_LIST_TITLE = "FOOL_LIST_TITLE"
+const val FOOD_LIST_TYPE = "FOOD_LIST_TYPE"
+const val WIFI_FROM_MAIN_SETTING = "WIFI_FROM_MAIN_SETTING"
+const val POLICY_FROM_MAIN_SETTING = "POLICY_FROM_MAIN_SETTING"
+const val MODE_ENTRANCE = "MODE_ENTRANCE"
+const val MODE_TYPE = "mode_type"
+const val LANGUAGE_FROM_SETTING = "LANGUAGE_FROM_SETTING"
+const val SCREENSAVER = "ScreenSaver"
+const val SOURCE_TAG = "source"
+const val NUMBER_TAG = "number"
+const val IS_LIKE_TAG = "isLike"
+const val RECIPES_EDITION_TAG = "recipesEdition"
+
+const val Favourite = 1
+const val History = 2
+const val Downloaded = 3
+
+const val Mode = 1
+const val Recipes = 2
+
+const val NetFood = 1
+const val LocalFood = 2
+
+const val CURRENT_LANGUAGE = "CURRENT_LANGUAGE"
+const val API_TOKEN = "API_TOKEN"
+const val LOGIN_TAG = "LOGIN_TAG"
+const val CURRENT_USER_ID_TAG = "CURRENT_USER_ID"
+
+const val EN = "EN"
+const val ZH = "ZH"
+const val JA = "JA"
+const val FR = "FR"
+
+const val TURN_UP_KEY_CODE = 19
+const val TURN_DOWN_KEY_CODE = 20
+const val PRESS_DOWN_KEY_CODE = 66
+
+val CURRENT_USER_ID = MMkvUtils.getLong(CURRENT_USER_ID_TAG) ?: 10001L

+ 27 - 0
BusinessCommon/src/main/java/com/develop/common/ui/CommonBVMActivity.kt

@@ -0,0 +1,27 @@
+package com.develop.common.ui
+
+import android.os.Bundle
+import androidx.viewbinding.ViewBinding
+import com.develop.base.mvvm.BaseViewModel
+
+
+/**
+ * 带业务逻辑的基类,带view model
+ */
+abstract class CommonBVMActivity<VB : ViewBinding, VM : BaseViewModel> :
+    CommonBindingActivity<VB>() {
+    protected lateinit var viewModel: VM
+
+    abstract fun createViewModel(): VM
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        viewModel = createViewModel()
+        lifecycle.addObserver(viewModel)
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        lifecycle.removeObserver(viewModel)
+    }
+}

+ 22 - 0
BusinessCommon/src/main/java/com/develop/common/ui/CommonBVMFragment.kt

@@ -0,0 +1,22 @@
+package com.develop.common.ui
+
+import android.os.Bundle
+import androidx.viewbinding.ViewBinding
+import com.develop.base.mvvm.BaseViewModel
+
+abstract class CommonBVMFragment<T : ViewBinding, VM : BaseViewModel> : CommonBindingFragment<T>() {
+    protected lateinit var viewModel: VM
+
+    abstract fun createViewModel(): VM
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        viewModel = createViewModel()
+        lifecycle.addObserver(viewModel)
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        lifecycle.removeObserver(viewModel)
+    }
+}

+ 176 - 0
BusinessCommon/src/main/java/com/develop/common/ui/CommonBindingActivity.kt

@@ -0,0 +1,176 @@
+package com.develop.common.ui
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.os.Bundle
+import android.os.IBinder
+import android.view.MotionEvent
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.EditText
+import androidx.viewbinding.ViewBinding
+import com.develop.base.ext.navigateTo
+import com.develop.base.mvvm.BaseBindingActivity
+import com.develop.base.util.MMkvUtils
+import com.develop.common.R
+import com.develop.common.dialog.CancelConfirmDialog
+import com.develop.common.dialog.PlainDialogView
+import com.develop.common.food_sdk.FoodSdkUtils
+import com.develop.common.food_sdk.GlobalDevEvent
+import com.develop.common.router.Screens
+import com.develop.common.tag.SCREENSAVER
+import com.develop.common.utils.TimeDownUtil
+import com.kuyuntech.cofarcooking.device.sdk.eventbus.event.DevPromptEvent
+import org.greenrobot.eventbus.Subscribe
+
+/**
+ * 带业务逻辑的基类
+ */
+abstract class CommonBindingActivity<T : ViewBinding> : BaseBindingActivity<T>() {
+
+    protected var hasShowScreenSaver = false
+
+    private val plainDialogView by lazy {
+        PlainDialogView(
+            this, R.layout.dialog_easy_view
+        )
+    }
+
+    private val screenSaverDialog by lazy {
+        CancelConfirmDialog()
+    }
+
+    private var timeDownUtil: TimeDownUtil? = null
+    private var screenSaverTime = 3 //minute
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        val time = MMkvUtils.getInt(SCREENSAVER)
+        if (time != 0) {
+            screenSaverTime = time
+        }
+        screenSaverDialog.onDialogClickListener =
+            object : CancelConfirmDialog.OnDialogClickListener {
+                override fun onConfirm() {
+                    navigateTo(Screens.Setting.SCREEN_SAVER)
+                }
+
+                override fun onCancel() {
+                    if (!hasShowScreenSaver) startScreenSaverCount()
+                }
+            }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        //设置屏幕为竖屏, 设置后会锁定方向
+        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+        if (!hasShowScreenSaver) {
+            startScreenSaverCount()
+        } else {
+            stopScreenSaverCount()
+        }
+    }
+
+    override fun onPause() {
+        super.onPause()
+        stopScreenSaverCount()
+    }
+
+    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
+        when (ev.action) {
+            MotionEvent.ACTION_UP -> if (!hasShowScreenSaver) startScreenSaverCount()
+            else -> stopScreenSaverCount()
+        }
+        if (ev.action == MotionEvent.ACTION_DOWN) {
+            //全局点击外面关闭软键盘
+            // 获得当前得到焦点的View,一般情况下就是EditText(特殊情况就是轨迹求或者实体案件会移动焦点)
+            val v = currentFocus
+            if (isShouldHideInput(v, ev)) {
+                hideSoftInput(v?.windowToken)
+            }
+        }
+        return super.dispatchTouchEvent(ev)
+    }
+
+    fun showPlainDialog(cancelable: Boolean = false) {
+        plainDialogView.showDialog(cancelable)
+    }
+
+    fun dismissPlainDialog() {
+        plainDialogView.hideDialog()
+    }
+
+    /**
+     * 隐藏软键盘
+     */
+    private fun hideSoftInput(token: IBinder?) {
+        if (token != null) {
+            val manager: InputMethodManager =
+                getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+            manager.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS)
+        }
+    }
+
+    /**
+     * 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
+     * 因为当用户点击EditText时没必要隐藏
+     */
+    private fun isShouldHideInput(v: View?, event: MotionEvent): Boolean {
+        if (v != null && v is EditText) {
+            val l = intArrayOf(0, 0)
+            v.getLocationInWindow(l)
+            val left = l[0]
+            val top = l[1]
+            val bottom = top + v.height
+            val right = (left + v.width)
+            return !(event.x > left && event.x < right && event.y > top && event.y < bottom)
+        }
+        // 如果焦点不是EditText则忽略,这个发生在视图刚绘制完,第一个焦点不在EditView上,和用户用轨迹球选择其他的焦点
+        return false
+    }
+
+    private fun startScreenSaverCount() {
+        if (FoodSdkUtils.isDevRunning()) {
+            return
+        }
+        stopScreenSaverCount()
+        val totalTime = screenSaverTime * 60 * 1000L
+        timeDownUtil = object : TimeDownUtil(totalTime, 1000) {
+            override fun onTick(millisUntilFinished: Long) {
+                if (millisUntilFinished == 30 * 1000L) {
+                    runOnUiThread {
+                        showScreenSaverDialog()
+                    }
+                }
+            }
+
+            override fun onFinish() {
+
+            }
+        }
+        timeDownUtil?.start()
+    }
+
+    private fun stopScreenSaverCount() {
+        timeDownUtil?.cancel()
+        timeDownUtil = null
+    }
+
+    private fun showScreenSaverDialog() {
+        screenSaverDialog.title = getString(R.string.screen_saver_title)
+        screenSaverDialog.showDialog(supportFragmentManager, "cancelConfirmDialog")
+    }
+
+    @Subscribe
+    fun onCookDevMsgEvent(event: DevPromptEvent) {
+        GlobalDevEvent.globalDevMsgEvent(event, supportFragmentManager)
+    }
+
+
+    override fun onDestroy() {
+        super.onDestroy()
+        GlobalDevEvent.dismissDialog()
+        dismissPlainDialog()
+    }
+}

+ 33 - 0
BusinessCommon/src/main/java/com/develop/common/ui/CommonBindingFragment.kt

@@ -0,0 +1,33 @@
+package com.develop.common.ui
+
+
+import androidx.viewbinding.ViewBinding
+
+import com.develop.base.mvvm.BaseBindingFragment
+import com.develop.common.R
+import com.develop.common.dialog.PlainDialogView
+
+abstract class CommonBindingFragment<T : ViewBinding> : BaseBindingFragment<T>() {
+
+
+    private val plainDialogView by lazy {
+        PlainDialogView(hostActivity, R.layout.dialog_easy_view)
+    }
+
+
+    fun showPlainDialog(cancelable: Boolean = false) {
+        if (hostActivity is CommonBindingActivity<*>) {
+            (hostActivity as CommonBindingActivity<*>).showPlainDialog(cancelable)
+        } else {
+            plainDialogView.showDialog(cancelable)
+        }
+    }
+
+    fun dismissPlainDialog() {
+        if (hostActivity is CommonBindingActivity<*>) {
+            (hostActivity as CommonBindingActivity<*>).dismissPlainDialog()
+        } else {
+            plainDialogView.hideDialog()
+        }
+    }
+}

+ 15 - 0
BusinessCommon/src/main/java/com/develop/common/utils/CommonKit.kt

@@ -0,0 +1,15 @@
+package com.develop.common.utils
+
+import com.develop.base.ext.timeStamp2Time
+
+ fun getTimeStr(time: Long): String {
+    val format = if (time >= 60 * 60) {
+        "HH:mm"
+    } else {
+        "mm:ss"
+    }
+    return timeStamp2Time(
+        time,
+        format
+    ) ?: ""
+}

+ 70 - 0
BusinessCommon/src/main/java/com/develop/common/utils/TimeDownUtil.kt

@@ -0,0 +1,70 @@
+package com.develop.common.utils
+
+import java.util.*
+
+abstract class TimeDownUtil {
+    private var mCountDownInterval: Long = 1000
+    private var mTimer: Timer? = null
+    private var mTimerTask: TimerTask? = null
+
+    /**
+     * 时钟回调的次数
+     */
+    private var mCount = 0
+
+    /**
+     * 倒计时时间,默认间隔单位为秒
+     *
+     * @param time 毫秒
+     */
+    constructor(time: Long) {
+        initTimer(time)
+    }
+
+    private fun initTimer(time: Long) {
+        mTimer = Timer()
+        mCount = (time / mCountDownInterval).toInt()
+        mTimerTask = object : TimerTask() {
+            override fun run() {
+                if (mCount > 0) {
+                    mCount--
+                    onTick(mCountDownInterval * mCount)
+                } else {
+                    onFinish()
+                    cancel()
+                }
+            }
+        }
+    }
+
+    /**
+     * 倒计时时间,默认单位为秒
+     *
+     * @param time
+     * @param countDownInterval 间隔时间,1000为1s
+     */
+    constructor(time: Long, countDownInterval: Long) {
+        mCountDownInterval = countDownInterval
+        initTimer(time)
+    }
+
+    fun start() {
+        mTimer?.schedule(mTimerTask, 0, mCountDownInterval)
+    }
+
+    /**
+     * Callback fired on regular interval.
+     *
+     * @param millisUntilFinished 距离结束还有多少时间
+     */
+    abstract fun onTick(millisUntilFinished: Long)
+
+    /**
+     * 倒计时结束的回调
+     */
+    abstract fun onFinish()
+    fun cancel() {
+        mTimer?.cancel()
+        mTimerTask?.cancel()
+    }
+}

+ 24 - 0
BusinessCommon/src/main/java/com/develop/common/utils/TimeUtil.kt

@@ -0,0 +1,24 @@
+package com.develop.common.utils
+
+object TimeUtil {
+
+    fun getTimes(second: Int, dst: IntArray) {
+        val h = (second / 3600)
+        val m = second % 3600 / 60
+        val s = second % 60
+        dst[0] = h
+        dst[1] = m
+        dst[2] = s
+    }
+
+    fun formatTime(src: IntArray): String {
+        val hStr = if (src[0] < 10) "0${src[0]}" else src[0].toString()
+        val mStr = if (src[1] < 10) "0${src[1]}" else src[1].toString()
+        val sStr = if (src[2] < 10) "0${src[2]}" else src[2].toString()
+        return if (src[0] > 0) {
+            "$hStr:$mStr"
+        }else {
+            "$mStr:$sStr"
+        }
+    }
+}

+ 0 - 0
BusinessCommon/src/main/java/com/develop/common/utils/TimerUtils.kt


Some files were not shown because too many files changed in this diff