diff --git a/.gitignore b/.gitignore
index a8b0d1d..aa724b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,35 +1,15 @@
-# ---> Android
-# Gradle files
-.gradle/
-build/
-
-# Local configuration file (sdk path, etc)
-local.properties
-
-# Log/OS Files
-*.log
-
-# Android Studio generated files and folders
-captures/
-.externalNativeBuild/
-.cxx/
-*.apk
-output.json
-
-# IntelliJ
*.iml
-.idea/
-misc.xml
-deploymentTargetDropDown.xml
-render.experimental.xml
-
-# Keystore files
-*.jks
-*.keystore
-
-# Google Services (e.g. APIs or Firebase)
-google-services.json
-
-# Android Profiling
-*.hprof
-
+.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
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b86273d
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..66149fe
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml
new file mode 100644
index 0000000..91f9558
--- /dev/null
+++ b/.idea/deviceManager.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..639c779
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..b2c751a
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..16660f1
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 0000000..8919852
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,104 @@
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.android)
+ id("com.google.devtools.ksp") version "2.0.21-1.0.27"
+}
+
+android {
+ namespace = "com.shuwei.dish.match"
+ compileSdk = 36
+
+ defaultConfig {
+ applicationId = "com.shuwei.dish.match"
+ minSdk = 29
+ targetSdk = 36
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ ndk {
+ //设置支持的SO库架构
+ abiFilters.addAll(listOf("armeabi", "armeabi-v7a"))
+ //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
+ }
+ }
+ signingConfigs {
+ create("debug_507") {
+ storeFile = file("../system.keystore")
+ storePassword = "android"
+ keyAlias = "wabon"
+ keyPassword = "android"
+ }
+ }
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ signingConfig = signingConfigs.getByName("debug_507")
+ }
+ debug {
+ //507扫码秤主板在android.buildTypes{}内增加
+ signingConfig = signingConfigs.getByName("debug_507")
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+ kotlinOptions {
+ jvmTarget = "11"
+ }
+ buildFeatures {
+ viewBinding = true
+ }
+ packagingOptions {
+ pickFirst("lib/armeabi-v7a/libserial_port.so")
+ pickFirst("lib/arme64-v8a/libserial_port.so")
+ }
+}
+
+dependencies {
+ implementation(fileTree("libs") { include("*.jar", "*.aar") })
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.appcompat)
+ implementation(libs.material)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+
+ implementation("com.squareup.okhttp3:okhttp:4.9.1")
+ implementation("com.google.code.gson:gson:2.10.1")
+// implementation("com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30")
+
+ implementation("io.github.cymchad:BaseRecyclerViewAdapterHelper4:4.1.2")
+
+ implementation("androidx.room:room-runtime:2.5.2")
+ ksp("androidx.room:room-compiler:2.5.2")
+ implementation("androidx.room:room-ktx:2.5.2") // Kotlin扩展
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
+ implementation("androidx.activity:activity-ktx:1.8.0")
+
+// implementation("biz.laenger.android:vpbs:0.0.6")
+
+ //必须 1.0.0 以上
+ implementation("io.github.scwang90:refresh-layout-kernel:3.0.0-alpha")
+ //核心必须依赖
+ implementation("io.github.scwang90:refresh-header-classics:3.0.0-alpha")
+ //经典刷新头
+ implementation("io.github.scwang90:refresh-header-radar:3.0.0-alpha")
+ //雷达刷新头
+ implementation("io.github.scwang90:refresh-header-falsify:3.0.0-alpha")
+ //虚拟刷新头
+ implementation("io.github.scwang90:refresh-header-material:3.0.0-alpha")
+ //谷歌刷新头
+ implementation("io.github.scwang90:refresh-header-two-level:3.0.0-alpha")
+ //二级刷新头
+ implementation("io.github.scwang90:refresh-footer-ball:3.0.0-alpha")
+ //球脉冲加载
+ implementation("io.github.scwang90:refresh-footer-classics:3.0.0-alpha")
+ //经典加载
+}
\ No newline at end of file
diff --git a/app/libs/WbAiThingsSDK.aar b/app/libs/WbAiThingsSDK.aar
new file mode 100644
index 0000000..af005b4
Binary files /dev/null and b/app/libs/WbAiThingsSDK.aar differ
diff --git a/app/libs/utilcode.jar b/app/libs/utilcode.jar
new file mode 100644
index 0000000..4992673
Binary files /dev/null and b/app/libs/utilcode.jar differ
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/release/app-release.apk b/app/release/app-release.apk
new file mode 100644
index 0000000..88b8238
Binary files /dev/null and b/app/release/app-release.apk differ
diff --git a/app/release/baselineProfiles/0/app-release.dm b/app/release/baselineProfiles/0/app-release.dm
new file mode 100644
index 0000000..b6b41bc
Binary files /dev/null and b/app/release/baselineProfiles/0/app-release.dm differ
diff --git a/app/release/baselineProfiles/1/app-release.dm b/app/release/baselineProfiles/1/app-release.dm
new file mode 100644
index 0000000..917e1a2
Binary files /dev/null and b/app/release/baselineProfiles/1/app-release.dm differ
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
new file mode 100644
index 0000000..4dd93a2
--- /dev/null
+++ b/app/release/output-metadata.json
@@ -0,0 +1,37 @@
+{
+ "version": 3,
+ "artifactType": {
+ "type": "APK",
+ "kind": "Directory"
+ },
+ "applicationId": "com.shuwei.dish.match",
+ "variantName": "release",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "attributes": [],
+ "versionCode": 1,
+ "versionName": "1.0",
+ "outputFile": "app-release.apk"
+ }
+ ],
+ "elementType": "File",
+ "baselineProfiles": [
+ {
+ "minApi": 28,
+ "maxApi": 30,
+ "baselineProfiles": [
+ "baselineProfiles/1/app-release.dm"
+ ]
+ },
+ {
+ "minApi": 31,
+ "maxApi": 2147483647,
+ "baselineProfiles": [
+ "baselineProfiles/0/app-release.dm"
+ ]
+ }
+ ],
+ "minSdkVersionForDexing": 29
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/shuwei/dish/match/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/shuwei/dish/match/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..7d9a778
--- /dev/null
+++ b/app/src/androidTest/java/com/shuwei/dish/match/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.shuwei.dish.match
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.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.shuwei.dish.shelves", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d328061
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/img.png b/app/src/main/img.png
new file mode 100644
index 0000000..a0858ee
Binary files /dev/null and b/app/src/main/img.png differ
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/DishPartAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/DishPartAdapter.kt
new file mode 100644
index 0000000..90ab830
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/DishPartAdapter.kt
@@ -0,0 +1,54 @@
+package com.shuwei.dish.match.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.ListItemDishCookBinding
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+
+class DishPartAdapter(list: MutableList) :
+ BaseQuickAdapter(list) {
+
+ inner class VH(var binding: ListItemDishCookBinding) : QuickViewHolder(binding.root)
+
+ override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
+ val inflater = LayoutInflater.from(context)
+ val binding = ListItemDishCookBinding.inflate(inflater, parent, false)
+ return VH(binding)
+ }
+
+ override fun onBindViewHolder(holder: VH, position: Int, item: CookFoodGoodsEntity?) {
+ holder.binding.run {
+ tvDishName.text = item!!.goodsName
+ tvDishType.text = if (item.materialType == 1) "主辅材:主材" else if (item.materialType == 2) "主辅材:辅材" else ""
+ tvDishWeight.text =
+ if (item.useWeight == null || item.useWeight == 0) "" else "${item.useWeight}克"
+ tvDishWeight.setTextColor(
+ ContextCompat.getColor(
+ context,
+ if (item.isSamplingPage) R.color.black999 else R.color.dish_green
+ )
+ )
+ ivOperateIcon.setImageResource(
+ if (item.isSamplingPage)
+ //采集页面
+ R.drawable.ic_delete
+ else
+ //制作页面
+ if (item.isSetFinished) R.drawable.ic_dish_selected
+ else R.drawable.ic_dish_unselected
+ )
+ root.run {
+ setBackgroundResource(
+ if (item.isItemClicked) R.drawable.shape_item_cook_dish
+ else R.drawable.shape_white_fb_15_corners
+ )
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/DishShowAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/DishShowAdapter.kt
new file mode 100644
index 0000000..7bf426f
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/DishShowAdapter.kt
@@ -0,0 +1,59 @@
+package com.shuwei.dish.match.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.databinding.ListItemDishBinding
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.visible
+
+class DishShowAdapter(list: MutableList) :
+ BaseQuickAdapter(list) {
+
+ inner class VH(var binding: ListItemDishBinding) : QuickViewHolder(binding.root)
+
+ override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
+ val inflater = LayoutInflater.from(context)
+ val binding = ListItemDishBinding.inflate(inflater, parent, false)
+ return VH(binding)
+ }
+
+ override fun onBindViewHolder(holder: VH, position: Int, item: FoodRecord?) {
+ holder.binding.run {
+ val isCooking = item!!.isCooking
+ val totalWeight = item.totalWeight ?: 0
+ tvDishName.text = item!!.foodName
+ if (isCooking) {
+ tvDishName.setTextColor(
+ ContextCompat.getColor(holder.itemView.context, R.color.black)
+ )
+ clBlock.setBackgroundResource(R.drawable.shape_white_fb_15_corners)
+ tvDishCount.visible()
+ tvDishCount.text = "制作统计:-kg"
+ tvShowState.text = "烹饪中"
+ } else if (totalWeight > 0) {
+ tvDishName.setTextColor(
+ ContextCompat.getColor(holder.itemView.context, R.color.dish_green)
+ )
+ clBlock.setBackgroundResource(R.drawable.shape_white_fb_15_corners)
+ tvDishCount.visible()
+ tvDishCount.text =
+ "累计统计:${totalWeight / 1000.0F}kg(${item.count}次)"
+ tvShowState.text = "${(item.foodWeight ?: 0) / 1000.0F}kg"
+ } else {
+ tvDishName.setTextColor(
+ ContextCompat.getColor(holder.itemView.context, R.color.black999)
+ )
+ clBlock.setBackgroundResource(R.drawable.shape_white_dash_15_corners)
+ tvDishCount.gone()
+ tvShowState.text = "-"
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/FoodRecordAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/FoodRecordAdapter.kt
new file mode 100644
index 0000000..7f6e7fd
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/FoodRecordAdapter.kt
@@ -0,0 +1,33 @@
+package com.shuwei.dish.match.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.databinding.ListItemDishRecordBinding
+import com.shuwei.dish.match.entity.FoodRecord
+
+class FoodRecordAdapter(list: MutableList) :
+ BaseQuickAdapter(list) {
+
+ inner class VH(var binding: ListItemDishRecordBinding) : QuickViewHolder(binding.root)
+
+ override fun onBindViewHolder(
+ holder: VH,
+ position: Int,
+ item: FoodRecord?
+ ) {
+ holder.binding.tvDishInfo.text = item?.foodName
+ }
+
+ override fun onCreateViewHolder(
+ context: Context,
+ parent: ViewGroup,
+ viewType: Int
+ ): VH {
+ val inflater = LayoutInflater.from(context)
+ val binding = ListItemDishRecordBinding.inflate(inflater, parent, false)
+ return VH(binding)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/GoodsInfoSearchAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/GoodsInfoSearchAdapter.kt
new file mode 100644
index 0000000..c4623f1
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/GoodsInfoSearchAdapter.kt
@@ -0,0 +1,49 @@
+package com.shuwei.dish.match.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.ListItemSearchGoodsInfoBinding
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+
+class GoodsInfoSearchAdapter(private var list: MutableList) :
+ BaseQuickAdapter(list) {
+
+ override fun onBindViewHolder(
+ holder: VH,
+ position: Int,
+ item: CookFoodGoodsEntity?
+ ) {
+ holder.binding.tvGoodsInfo.run {
+ text = item?.goodsName
+ setBackgroundResource(
+ if (item?.isClicked == true) R.drawable.shape_green_stroke
+ else R.drawable.shape_white_12_corners
+ )
+ setTextColor(
+ ContextCompat.getColor(
+ context,
+ if (item?.isClicked == true) R.color.dish_green
+ else R.color.black666
+ )
+ )
+ }
+ }
+
+ override fun onCreateViewHolder(
+ context: Context,
+ parent: ViewGroup,
+ viewType: Int
+ ): VH {
+ val binding =
+ ListItemSearchGoodsInfoBinding.inflate(LayoutInflater.from(context), parent, false)
+ return VH(binding)
+ }
+
+ inner class VH(var binding: ListItemSearchGoodsInfoBinding) : QuickViewHolder(binding.root)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/HomeModeAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/HomeModeAdapter.kt
new file mode 100644
index 0000000..233651d
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/HomeModeAdapter.kt
@@ -0,0 +1,46 @@
+package com.shuwei.dish.match.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.ListItemHomeModeBinding
+import com.shuwei.dish.match.entity.HomeModeBean
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.visible
+
+class HomeModeAdapter(list: MutableList) : BaseQuickAdapter(list) {
+
+ inner class VH(var binding: ListItemHomeModeBinding) : QuickViewHolder(binding.root)
+
+ override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
+ val binding = ListItemHomeModeBinding.inflate(LayoutInflater.from(context), parent, false)
+ return VH(binding)
+ }
+
+ override fun onBindViewHolder(holder: VH, position: Int, item: HomeModeBean?) {
+ holder.binding.run {
+ tvModeName.text = item!!.modeName
+ tvModeDesc.text = item.modeDesc
+ ivModeIcon.setImageResource(item.modeIconId)
+ tvLockRemind.run {
+ if (item.isLocked) visible() else gone()
+ }
+ var modeNameColor = R.color.mode_name
+ var modeDescColor = R.color.mode_desc
+ var rightIconId = R.drawable.ic_arrow_right
+ if (item.isLocked) {
+ modeNameColor = R.color.mode_name
+ modeDescColor = R.color.mode_desc
+ rightIconId = R.drawable.ic_lock
+ }
+ this.ivRightIcon.setImageResource(rightIconId)
+ tvModeName.setTextColor(ContextCompat.getColor(root.context, modeNameColor))
+ tvModeDesc.setTextColor(ContextCompat.getColor(root.context, modeDescColor))
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/SamplingAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/SamplingAdapter.kt
new file mode 100644
index 0000000..d234ba6
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/SamplingAdapter.kt
@@ -0,0 +1,52 @@
+package com.shuwei.dish.match.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.databinding.ListItemDishBinding
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.visible
+
+class SamplingAdapter(list: MutableList) :
+ BaseQuickAdapter(list) {
+
+ inner class VH(var binding: ListItemDishBinding) : QuickViewHolder(binding.root)
+
+ override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
+ val inflater = LayoutInflater.from(context)
+ val binding = ListItemDishBinding.inflate(inflater, parent, false)
+ return VH(binding)
+ }
+
+ override fun onBindViewHolder(holder: VH, position: Int, item: FoodRecord?) {
+ holder.binding.run {
+ val isCooking = item!!.isCooking
+ clBlock.setBackgroundResource(R.drawable.shape_white_fb_15_corners)
+ val totalWeight = item!!.totalWeight ?: 0
+ tvDishName.run {
+ text = item!!.foodName
+ setTextColor(
+ ContextCompat.getColor(
+ holder.itemView.context,
+ if (isCooking) R.color.black else R.color.dish_green
+ )
+ )
+ }
+ tvDishCount.visible()
+ if (isCooking) {
+ tvDishCount.text = "制作统计:-kg"
+ tvShowState.text = "烹饪中"
+ } else {
+ val useWeight = if (totalWeight > 0) totalWeight else (item.foodWeight ?: 0)
+ tvDishCount.text = "累计统计:${useWeight / 1000.0F}kg(${item.count}次)"
+ tvShowState.text = "${(item.foodWeight ?: 0) / 1000.0F}kg"
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/SeasoningCellTool.kt b/app/src/main/java/com/shuwei/dish/match/adapter/SeasoningCellTool.kt
new file mode 100644
index 0000000..813fa1b
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/SeasoningCellTool.kt
@@ -0,0 +1,132 @@
+package com.shuwei.dish.match.adapter
+
+import android.annotation.SuppressLint
+import android.widget.TextView
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.dialog.BottomDialog2
+import com.shuwei.dish.match.entity.SeasoningEntity
+import com.shuwei.dish.match.ui.DeviceSettingActivity
+import com.shuwei.dish.match.ui.SubmitDishActivity
+import com.shuwei.dish.match.utils.DataUtil
+
+object SeasoningCellTool {
+ private val TAG = "SeasoningCellTool"
+
+ private val list = mutableListOf()
+ private lateinit var activity: BaseActivity
+ private var pageType: Int = 0
+
+ @SuppressLint("StaticFieldLeak")
+ private lateinit var cellAdapter: TextCellAdapter
+
+ @SuppressLint("NotifyDataSetChanged")
+ fun loadData(
+ activity: BaseActivity,
+ initList: MutableList? = null,
+ recyclerView: RecyclerView,
+ tvCell: TextView,
+ pageType: Int = 0
+ ) {
+ this.activity = activity
+ this.pageType = pageType
+ list.clear()
+ val tempList = buildData(initList, pageType)
+ list.addAll(tempList)
+ recyclerView.run {
+ if (adapter == null) {
+ layoutManager = GridLayoutManager(
+ activity,
+ 3,
+ GridLayoutManager.VERTICAL,
+ false
+ )
+ cellAdapter = TextCellAdapter(list).apply {
+ onCellClick = { position ->
+ val currentAddress = DataUtil.getWeighAddressArray().get(position)
+ BottomDialog2(
+ weighIndex = position,
+ weighAddress = currentAddress,
+ clickName = list[position].goodsName
+ ).show(activity) { item ->
+ list[position].let { current ->
+ syncItem(current, item)
+ //3-调料
+ current.materialType = 3
+ current.sort = position
+ }
+ notifyItemChanged(position)
+ if (position == 14) {
+ syncItem(list[10], list[14])
+ syncItem(list[11], list[14])
+ syncItem(list[13], list[14])
+ TextCellAdapter.loadCell(tvCell, list[14])
+ notifyItemChanged(10)
+ notifyItemChanged(11)
+ notifyItemChanged(13)
+ notifyItemChanged(14)
+ }
+ if (activity is DeviceSettingActivity) {
+ //activity.list = list
+ activity.saveSeasoning(list[position])
+ }
+ }
+ }
+ }
+ adapter = cellAdapter
+ } else {
+ cellAdapter.notifyDataSetChanged()
+ }
+ if (activity is SubmitDishActivity) {
+ activity.updateSeasoningList(list)
+ }
+ }
+ if (pageType == 1) {
+ tvCell.setOnClickListener {
+ cellAdapter.onCellClick?.invoke(14)
+ }
+ }
+ TextCellAdapter.loadCell(tvCell, list[list.size - 1])
+ }
+
+ private fun buildData(
+ initList: MutableList?,
+ pageType: Int = 0
+ ): MutableList {
+ val list = mutableListOf()
+ repeat(15) {
+ list.add(SeasoningEntity().apply { this.pageType = pageType })
+ }
+ if (initList.isNullOrEmpty().not()) {
+ initList.forEach {
+ list[it.sort] = it.apply { this.pageType = pageType }
+ }
+ var lastItem = initList.firstOrNull { it.sort == 14 }
+ lastItem = lastItem ?: list[list.size - 1]
+ list[10] = lastItem
+ list[11] = lastItem
+ list[13] = lastItem
+ }
+ return list
+ }
+
+ private fun syncItem(item: SeasoningEntity, newItem: SeasoningEntity) {
+ item.run {
+ goodsId = newItem.goodsId
+ goodsName = newItem.goodsName
+ goodsOrRelationCode = newItem.goodsOrRelationCode
+ relateionType = newItem.relateionType
+ materialType = newItem.materialType
+ allEdible = newItem.allEdible
+ useWeight = newItem.useWeight
+ popularName = newItem.popularName
+ canteenId = newItem.canteenId
+ relateionType_dictText = newItem.relateionType_dictText
+
+ foodId = newItem.foodId
+ sort = newItem.sort
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/SeasoningSearchAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/SeasoningSearchAdapter.kt
new file mode 100644
index 0000000..1477df3
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/SeasoningSearchAdapter.kt
@@ -0,0 +1,49 @@
+package com.shuwei.dish.match.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.ListItemSearchGoodsInfoBinding
+import com.shuwei.dish.match.entity.SeasoningEntity
+
+class SeasoningSearchAdapter(private var list: MutableList) :
+ BaseQuickAdapter(list) {
+
+ override fun onBindViewHolder(
+ holder: VH,
+ position: Int,
+ item: SeasoningEntity?
+ ) {
+ holder.binding.tvGoodsInfo.run {
+ text = item?.goodsName
+ setBackgroundResource(
+ if (item?.isClicked == true) R.drawable.shape_green_stroke
+ else R.drawable.shape_white_12_corners
+ )
+ setTextColor(
+ ContextCompat.getColor(
+ context,
+ if (item?.isClicked == true) R.color.dish_green
+ else R.color.black666
+ )
+ )
+ }
+ }
+
+ override fun onCreateViewHolder(
+ context: Context,
+ parent: ViewGroup,
+ viewType: Int
+ ): VH {
+ val binding =
+ ListItemSearchGoodsInfoBinding.inflate(LayoutInflater.from(context), parent, false)
+ return VH(binding)
+ }
+
+ inner class VH(var binding: ListItemSearchGoodsInfoBinding) : QuickViewHolder(binding.root)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/TextCellAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/TextCellAdapter.kt
new file mode 100644
index 0000000..69deaca
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/TextCellAdapter.kt
@@ -0,0 +1,117 @@
+package com.shuwei.dish.match.adapter
+
+import android.graphics.Typeface
+import android.text.SpannableStringBuilder
+import android.text.style.AbsoluteSizeSpan
+import android.text.style.ForegroundColorSpan
+import android.text.style.LineHeightSpan
+import android.text.style.StyleSpan
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.toColorInt
+import androidx.recyclerview.widget.RecyclerView
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.ListItemCellBinding
+import com.shuwei.dish.match.entity.SeasoningEntity
+import com.shuwei.dish.match.utils.ext.appendText
+import com.shuwei.dish.match.utils.ext.buildSpannableString
+import com.shuwei.dish.match.utils.ext.clickWithDebounce
+import com.shuwei.dish.match.utils.ext.dp
+import com.shuwei.dish.match.utils.ext.invisible
+import com.shuwei.dish.match.utils.ext.visible
+
+class TextCellAdapter(var list: MutableList) :
+ RecyclerView.Adapter() {
+
+ inner class VH(var binding: ListItemCellBinding) : QuickViewHolder(binding.root)
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
+ val inflater = LayoutInflater.from(parent.context)
+ val binding = ListItemCellBinding.inflate(inflater, parent, false)
+ return VH(binding)
+ }
+
+ override fun onBindViewHolder(holder: VH, position: Int) {
+ val item = list[position]
+ holder.binding.run {
+ if (position == 10 || position == 11 || position == 13 || position == 14) {
+ root.invisible()
+ } else {
+ root.visible()
+ }
+ loadCell(tvCell, item)
+ //root.setBackgroundResource(R.color.dish_green)
+ (root.layoutParams as RecyclerView.LayoutParams).let {
+// it.bottomMargin = 15.dp
+ it.width = 226.dp
+ it.height = 120.dp
+// it.rightMargin = 0
+// it.leftMargin = if (position % 3 == 0) 0 else 15.dp
+
+ it.leftMargin = 7.dp
+ it.rightMargin = 8.dp
+ it.topMargin = 7.dp
+ it.bottomMargin = 8.dp
+ }
+ if (item.pageType == 1) {
+ root.clickWithDebounce { onCellClick?.invoke(position) }
+ }
+ }
+ }
+
+ override fun getItemCount() = list.size
+
+ var onCellClick: ((positon: Int) -> Unit)? = null
+
+ companion object {
+ fun loadCell(tvCell: TextView, item: SeasoningEntity) {
+ if (item.goodsName.isNullOrBlank()) {
+ tvCell.run {
+ text = "未配置"
+ setTextColor(ContextCompat.getColor(context, R.color.black999))
+ }
+ } else {
+// if (item.pageType == 1) {
+// tvCell.run {
+// text = item.goodsName
+// setTextColor(ContextCompat.getColor(context, R.color.black))
+// }
+// } else {
+ tvCell.text = getTextSpan(item)
+// }
+ }
+ }
+
+ fun getTextSpan(item: SeasoningEntity): SpannableStringBuilder {
+ val endIndex = if (item.sort == 14) 10 else 6
+ var name = item.goodsName!!
+ if (name.length > endIndex) {
+ name = "${name.substring(0, endIndex)}…"
+ }
+ return buildSpannableString {
+ appendText(
+ name,
+ ForegroundColorSpan("#000000".toColorInt()),
+ StyleSpan(Typeface.BOLD),
+ AbsoluteSizeSpan(28, true),
+ LineHeightSpan { text, start, end, spanstartv, v, fm ->
+ fm.descent += 10.dp // 增加行间距
+ }
+ )
+ append("\n")
+
+ val weight = item.useWeight ?: 0
+ val weightColor = if (weight == 0) "#999999" else "#00BC71"
+ appendText(
+ "${weight}g",
+ ForegroundColorSpan(weightColor.toColorInt()),
+ AbsoluteSizeSpan(30, true)
+ )
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt b/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt
new file mode 100644
index 0000000..4ed47a0
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt
@@ -0,0 +1,163 @@
+package com.shuwei.dish.match.base
+
+import android.content.Intent
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.activity.enableEdgeToEdge
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.ActivityBaseBinding
+import com.shuwei.dish.match.dialog.Loading
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.ui.HomeActivity.Companion.TAG
+import com.shuwei.dish.match.utils.ActivityManager
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.put
+import com.shuwei.dish.match.utils.ext.toast
+import java.time.LocalDateTime
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.util.Locale
+
+@Suppress("DEPRECATION")
+open class BaseActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityBaseBinding
+ private var launcher: ActivityResultLauncher? = null
+ private var launchCallback: ((Intent?) -> Unit)? = null
+
+ public fun launch(cls: Class<*>, launchCallback: (Intent?) -> Unit) {
+ this.launchCallback = launchCallback
+ launcher?.launch(Intent(this, cls))
+ }
+
+ public fun launch(intent: Intent, launchCallback: (Intent?) -> Unit) {
+ this.launchCallback = launchCallback
+ launcher?.launch(intent)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ ActivityManager.addActivity(this)
+ binding = ActivityBaseBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ statusBarDarkFont(enable = false)
+ launcher =
+ registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ if (result.resultCode == RESULT_OK) {
+ launchCallback?.invoke(result.data)
+ }
+ }
+
+// window.setDecorFitsSystemWindows(false) // 启用 Edge-to-Edge
+// window.insetsController?.apply {
+// hide(WindowInsets.Type.statusBars()) // 隐藏状态栏
+// systemBarsBehavior =
+// WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE // 滑动时临时显示
+// }
+ binding.llTitleBar.gone()
+ binding.ivBack.setOnClickListener { finish() }
+ }
+
+ override fun onDestroy() {
+ dismissLoading()
+ super.onDestroy()
+ ActivityManager.removeActivity(this)
+ }
+
+ fun hideStatusBar() {
+ enableEdgeToEdge()
+// val uiOptions = (View.SYSTEM_UI_FLAG_FULLSCREEN // 隐藏状态栏
+// or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // 隐藏导航栏(可选)
+ window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
+ }
+
+ fun statusBarDarkFont(enable: Boolean) {
+ //window.decorView.systemUiVisibility = if (enable) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR else 0
+ val color = ContextCompat.getColor(this,
+ if (enable) R.color.black else R.color.white
+ )
+ binding.tvLeftTime.setTextColor(color)
+ binding.tvRightTime.setTextColor(color)
+ }
+
+ fun setTitleBar(
+ titleBarAction: ((FrameLayout) -> Unit)? = null,
+ backAction: ((ImageView) -> Unit)? = null,
+ titleAction: ((TextView) -> Unit)? = null,
+ rightIconActon: ((ImageView) -> Unit)? = null
+ ) {
+ titleBarAction?.invoke(binding.llTitleBar)
+ backAction?.invoke(binding.ivBack)
+ titleAction?.invoke(binding.tvTitle)
+ rightIconActon?.invoke(binding.ivRightIcon)
+ }
+
+ public fun setHeaderBackground(isHomePage: Boolean = false) {
+ binding.ivHeaderBg.setImageResource(
+ if (isHomePage) R.drawable.bg_home_page else R.drawable.bg_other_page
+ )
+ }
+
+ override fun setContentView(view: View?) {
+ if (view == binding.root) {
+ super.setContentView(view)
+ } else {
+ binding.flContainer.addView(view)
+ }
+ }
+
+ private fun updateDateTime() {
+ val formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE***HH:mm:ss", Locale.CHINA)
+ val dateTime = formatter.format(LocalDateTime.now(ZoneId.of("Asia/Shanghai")))
+ val arr = dateTime.split("***")
+ binding.tvRightTime.text = arr[0]
+ binding.tvLeftTime.text = arr[1]
+ }
+
+ private val handler = Handler(Looper.getMainLooper())
+ private val updateTask = object : Runnable {
+ override fun run() {
+ updateDateTime()
+ handler.postDelayed(this, 1000)
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ hideStatusBar()
+ handler.post(updateTask)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ handler.removeCallbacks(updateTask)
+ }
+
+ fun showLoading() {
+ Loading.show(this)
+ }
+
+ fun dismissLoading() {
+ Loading.dismiss()
+ }
+
+ fun delayDismissLoading() {
+ window.decorView.postDelayed({
+ Loading.dismiss()
+ },500)
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/base/BaseApp.kt b/app/src/main/java/com/shuwei/dish/match/base/BaseApp.kt
new file mode 100644
index 0000000..7647d0f
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/base/BaseApp.kt
@@ -0,0 +1,36 @@
+package com.shuwei.dish.match.base
+
+import android.app.Application
+import android.content.Context
+import android.content.SharedPreferences
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.db.DatabaseProvider
+
+class BaseApp : Application() {
+
+ val database by lazy { DatabaseProvider(this).instance }
+
+ var token: String? = null
+ var androidId: String? = null
+
+ override fun onCreate() {
+ super.onCreate()
+ instance = this
+ }
+
+ companion object {
+ @Volatile
+ private var sharedPref: SharedPreferences? = null
+
+ public var instance: BaseApp? = null
+ fun getSharedPref(): SharedPreferences? {
+ if (sharedPref != null) {
+ return sharedPref
+ }
+ val saveName = instance?.getString(R.string.sp_save_name)
+ sharedPref = instance?.getSharedPreferences(saveName, Context.MODE_PRIVATE)
+ return sharedPref
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/base/BaseFragment.kt b/app/src/main/java/com/shuwei/dish/match/base/BaseFragment.kt
new file mode 100644
index 0000000..2167f3a
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/base/BaseFragment.kt
@@ -0,0 +1,9 @@
+package com.shuwei.dish.match.base
+
+import androidx.fragment.app.Fragment
+
+open class BaseFragment : Fragment() {
+
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/base/BaseReq.kt b/app/src/main/java/com/shuwei/dish/match/base/BaseReq.kt
new file mode 100644
index 0000000..ce222f8
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/base/BaseReq.kt
@@ -0,0 +1,10 @@
+package com.shuwei.dish.match.base
+
+class BaseReq {
+ var code: Int? = null
+ var success: Boolean? = null
+ var data: T? = null
+ var message: String? = null
+ var result: T? = null
+ var msg: String? = null
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/db/AppDatabase.kt b/app/src/main/java/com/shuwei/dish/match/db/AppDatabase.kt
new file mode 100644
index 0000000..1711c17
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/db/AppDatabase.kt
@@ -0,0 +1,174 @@
+package com.shuwei.dish.match.db
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import com.shuwei.dish.match.db.dao.AppDao
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.SeasoningEntity
+
+
+// 步骤1:更新版本号
+@Database(
+ // 添加所有实体类
+ entities = [
+ SeasoningEntity::class,
+ CookFoodEntity::class,
+ CookFoodGoodsEntity::class,
+ ],
+ version = 6,
+ exportSchema = true
+)
+abstract class AppDatabase : RoomDatabase() {
+// abstract fun seasoningDao(): SeasoningDao
+// abstract fun cookFoodDao(): CookFoodDao
+// abstract fun cookFoodGoodsDao(): CookFoodGoodsDao
+
+ abstract fun appDao(): AppDao
+
+}
+
+// 步骤2:创建Migration对象
+val MIGRATION_1_2 = MigrationImpl(1, 2) { db ->
+ // 获取SQLite版本
+ runCatching {
+ // 使用兼容方案
+ db.beginTransaction()
+ db.execSQL(
+ """
+ CREATE TABLE `dm_seasoning_new` (
+ `id` INTEGER NOT NULL,
+ `name` TEXT,
+ `weight` INTEGER,
+ `sort` INTEGER NOT NULL,
+ `isDel` INTEGER NOT NULL,
+ `createTime` INTEGER NOT NULL,
+ PRIMARY KEY(`id`)
+ )
+ """
+ )
+
+ db.execSQL(
+ """
+ INSERT INTO dm_seasoning_new
+ SELECT id, name, weight, sort, isDel, create_time
+ FROM dm_seasoning
+ """
+ )
+
+ db.execSQL("DROP TABLE dm_seasoning")
+ db.execSQL("ALTER TABLE dm_seasoning_new RENAME TO dm_seasoning")
+ // 执行上述临时表方案
+ db.setTransactionSuccessful()
+ }.onFailure {
+ it.printStackTrace()
+ }
+ db.endTransaction()
+}
+
+val MIGRATION_3_4 = MigrationImpl(3, 4) { db ->
+ db.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `dm_cook_food` (
+ `foodId` INTEGER PRIMARY KEY NOT NULL,
+ `foodName` TEXT,
+ `canteenId` INTEGER,
+ `cookedFoodWeight` INTEGER NOT NULL,
+ `isDel` INTEGER NOT NULL,
+ `createTime` TEXT NOT NULL
+ )
+ """
+ )
+
+ db.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `dm_cook_food_goods` (
+ `goodsId` INTEGER PRIMARY KEY NOT NULL,
+ `goodsName` TEXT,
+ `foodId` INTEGER NOT NULL,
+ `relateionType` INTEGER NOT NULL,
+ `allEdible` INTEGER NOT NULL,
+ `useWeight` INTEGER NOT NULL,
+ `isDel` INTEGER NOT NULL,
+ `createTime` TEXT NOT NULL
+ )
+ """
+ )
+}
+
+val MIGRATION_4_5 = MigrationImpl(4, 5) { db ->
+ db.execSQL("ALTER TABLE dm_cook_food_goods ADD sort INTEGER DEFAULT (0) NOT NULL")
+}
+val MIGRATION_5_6 = MigrationImpl(5, 6) { db ->
+ runCatching {
+ db.beginTransaction()
+ db.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `dm_cook_food_goods_new` (
+ `id` INTEGER PRIMARY KEY NOT NULL,
+ `goodsId` INTEGER NOT NULL,
+ `goodsName` TEXT,
+ `foodId` INTEGER NOT NULL,
+ `relateionType` INTEGER NOT NULL,
+ `allEdible` INTEGER NOT NULL,
+ `useWeight` INTEGER NOT NULL,
+ `sort` INTEGER NOT NULL DEFAULT 0,
+ `isDel` INTEGER NOT NULL,
+ `createTime` TEXT NOT NULL
+ )
+ """
+ )
+ db.execSQL(
+ """
+ INSERT INTO dm_cook_food_goods_new
+ SELECT NULL, goodsId, goodsName, foodId, relateionType, allEdible, useWeight, sort, isDel, createTime
+ FROM dm_cook_food_goods
+ """
+ )
+
+ db.execSQL("DROP TABLE dm_cook_food_goods")
+ db.execSQL("ALTER TABLE dm_cook_food_goods_new RENAME TO dm_cook_food_goods")
+ // 执行上述临时表方案
+ db.setTransactionSuccessful()
+ }.onFailure {
+ it.printStackTrace()
+ }
+ db.endTransaction()
+}
+
+class DatabaseProvider(private val context: Context) {
+ // 单例模式确保全局唯一实例
+ val instance: AppDatabase by lazy {
+ Room.databaseBuilder(
+ context.applicationContext,
+ AppDatabase::class.java,
+ "app_dish_match.db"
+ )
+ .addCallback(object : RoomDatabase.Callback() {
+ override fun onCreate(db: SupportSQLiteDatabase) {
+ // 数据库首次创建时初始化数据
+ }
+ })
+// .addMigrations(MIGRATION_1_2)
+// .addMigrations(MIGRATION_3_4)
+// .addMigrations(MIGRATION_4_5)
+// .addMigrations(MIGRATION_5_6)
+ .build()
+ }
+}
+
+class MigrationImpl(
+ startVersion: Int,
+ endVersion: Int,
+ private val block: (db: SupportSQLiteDatabase) -> Unit
+) : Migration(startVersion, endVersion) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ block(database)
+ }
+
+}
+
diff --git a/app/src/main/java/com/shuwei/dish/match/db/BaseDatabase.kt b/app/src/main/java/com/shuwei/dish/match/db/BaseDatabase.kt
new file mode 100644
index 0000000..e4a7b1d
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/db/BaseDatabase.kt
@@ -0,0 +1,34 @@
+package com.shuwei.dish.match.db
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Update
+
+
+// 1. 定义基础实体接口
+interface BaseEntity {
+}
+
+//定义回调接口
+interface OnCompleteListener {
+ fun onComplete()
+}
+
+// 2. 封装通用DAO操作
+@Dao
+interface BaseDao {
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insert(item: T): Long
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insertAll(items: MutableList): Array
+
+ @Update
+ suspend fun update(item: T)
+
+ @Delete
+ suspend fun delete(item: T)
+
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/db/DatabaseRepository.kt b/app/src/main/java/com/shuwei/dish/match/db/DatabaseRepository.kt
new file mode 100644
index 0000000..a42d059
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/db/DatabaseRepository.kt
@@ -0,0 +1,141 @@
+package com.shuwei.dish.match.db
+
+import com.shuwei.dish.match.db.dao.AppDao
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.SeasoningEntity
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+
+class AppRepository(val appDao: AppDao) {
+
+ suspend fun insertCookFood(item: CookFoodEntity) = withContext(Dispatchers.IO) {
+ appDao.insertCookFood(item)
+ }
+
+ suspend fun updateCookFood(item: CookFoodEntity) = withContext(Dispatchers.IO) {
+ appDao.updateCookFood(item)
+ }
+
+ suspend fun getCookFoodById(foodId: String, cookMode: Int) = withContext(Dispatchers.IO) {
+ appDao.getCookFoodById(foodId, cookMode)
+ }
+
+ suspend fun getCookFoodList(cookMode: Int) = withContext(Dispatchers.IO) {
+ appDao.getCookFoodList(cookMode)
+ }
+
+ suspend fun countCookFood(cookMode: Int) = withContext(Dispatchers.IO) {
+ appDao.countCookFood(cookMode)
+ }
+
+ suspend fun deleteCookFood(foodId: String, cookMode: Int) = withContext(Dispatchers.IO) {
+ appDao.deleteCookFood(foodId, cookMode)
+ }
+
+ suspend fun deleteCookFoodGoodsList(foodId: String) = withContext(Dispatchers.IO) {
+ appDao.deleteCookFoodGoodsList(foodId)
+ }
+ //--------------------------------------------------------------------------------------------
+
+ suspend fun insertGoods(item: CookFoodGoodsEntity) = withContext(Dispatchers.IO) {
+ appDao.insertGoods(item)
+ }
+
+ suspend fun insertGoodsList(items: MutableList) =
+ withContext(Dispatchers.IO) {
+ appDao.insertGoodsList(items)
+ }
+
+ suspend fun updateGoods(item: CookFoodGoodsEntity) = withContext(Dispatchers.IO) {
+ appDao.updateGoods(item)
+ }
+
+ suspend fun getCookFoodGoodsList(foodId: String) = withContext(Dispatchers.IO) {
+ appDao.getCookFoodGoodsList(foodId)
+ }
+
+ suspend fun getCookFoodGoodsListByType(
+ foodId: String,
+ materialType: Int
+ ) = withContext(Dispatchers.IO) {
+ appDao.getCookFoodGoodsListByType(foodId, materialType)
+ }
+ //--------------------------------------------------------------------------------------------
+
+ suspend fun getSeasoningById(id: Long) = withContext(Dispatchers.IO) {
+ appDao.getSeasoningById(id)
+ }
+
+ suspend fun getSeasoningBySort(sort:Int) = withContext(Dispatchers.IO) {
+ appDao.getSeasoningBySort(sort)
+ }
+
+ suspend fun getSeasoningByGoodsId(goodsId: Int) = withContext(Dispatchers.IO) {
+ appDao.getSeasoningByGoodsId(goodsId)
+ }
+
+ suspend fun getAllStream() = withContext(Dispatchers.IO) {
+ appDao.getAllStream()
+ }
+
+ suspend fun search(query: String) = withContext(Dispatchers.IO) {
+ appDao.search(query)
+ }
+
+ suspend fun deleteBatch() = withContext(Dispatchers.IO) {
+ appDao.deleteBatch()
+ }
+
+ suspend fun deleteEmptySeasoning() = withContext(Dispatchers.IO) {
+ appDao.deleteEmptySeasoning()
+ }
+
+ suspend fun insertSeasoningList(items: MutableList) =
+ withContext(Dispatchers.IO) {
+ appDao.insertSeasoningList(items)
+ }
+
+ suspend fun updateSeasoning(item: SeasoningEntity) = withContext(Dispatchers.IO) {
+ appDao.updateSeasoning(item)
+ }
+
+ suspend fun insertSeasoning(item: SeasoningEntity) = withContext(Dispatchers.IO) {
+ appDao.insertSeasoning(item)
+ }
+}
+//
+//class SeasoningRepository(val seasoningDao: SeasoningDao) {
+// val seasoningList: Flow> = seasoningDao.getAllStream()
+//
+// fun addSeasoning(item: SeasoningEntity) = withContext(Dispatchers.IO) {
+// seasoningDao.insert(item)
+// }
+//
+// fun searchSeasoning(query: String) = withContext(Dispatchers.IO) {
+// seasoningDao.search(query)
+// }
+//}
+//
+//class CookFoodRepository(val cookFoodDao: CookFoodDao) {
+// fun getCookFood(foodId: String, cookMode:Int = 0) = withContext(Dispatchers.IO) {
+// cookFoodDao.getCookFoodById(foodId, cookMode)
+// }
+//
+// fun getCookFoodByList(cookMode:Int = 0) = withContext(Dispatchers.IO) {
+// cookFoodDao.getCookFoodList(cookMode)
+// }
+//
+// fun countCookFood(cookMode:Int = 0)= withContext(Dispatchers.IO) {
+// cookFoodDao.countCookFood(cookMode)
+// }
+//}
+//
+//class CookFoodGoodsRepository(val cookFoodGoodsDao: CookFoodGoodsDao) {
+// fun getFoodGoodsList(foodId: String) = withContext(Dispatchers.IO) {
+// cookFoodGoodsDao.getCookFoodGoodsList(foodId)
+// }
+//
+//}
+
diff --git a/app/src/main/java/com/shuwei/dish/match/db/dao/AppDao.kt b/app/src/main/java/com/shuwei/dish/match/db/dao/AppDao.kt
new file mode 100644
index 0000000..418a5ad
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/db/dao/AppDao.kt
@@ -0,0 +1,90 @@
+package com.shuwei.dish.match.db.dao
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import androidx.room.Update
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.SeasoningEntity
+import kotlinx.coroutines.flow.Flow
+
+@Dao
+interface AppDao {
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insertCookFood(item: CookFoodEntity): Long
+
+ @Update
+ suspend fun updateCookFood(item: CookFoodEntity)
+
+ @Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND foodId = :foodId AND cookMode = :cookMode")
+ suspend fun getCookFoodById(foodId: String, cookMode: Int): CookFoodEntity?
+
+ @Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND cookMode = :cookMode ORDER BY createTime DESC")
+ suspend fun getCookFoodList(cookMode: Int): MutableList?
+
+ @Query("SELECT count(1) FROM dm_cook_food WHERE isDel = 0 AND cookMode = :cookMode")
+ suspend fun countCookFood(cookMode: Int): Int
+
+ @Query("DELETE FROM dm_cook_food WHERE foodId = :foodId AND cookMode = :cookMode")
+ suspend fun deleteCookFood(foodId: String, cookMode: Int)
+
+ //--------------------------------------------------------------------------------------------
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insertGoods(item: CookFoodGoodsEntity): Long
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insertGoodsList(items: MutableList): Array
+
+ @Update
+ suspend fun updateGoods(item: CookFoodGoodsEntity)
+
+ @Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId")
+ suspend fun getCookFoodGoodsList(foodId: String): MutableList
+
+ @Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId AND materialType = :materialType")
+ suspend fun getCookFoodGoodsListByType(
+ foodId: String,
+ materialType: Int
+ ): MutableList
+
+ @Query("DELETE FROM dm_cook_food_goods WHERE foodId = :foodId")
+ suspend fun deleteCookFoodGoodsList(foodId: String)
+
+ //--------------------------------------------------------------------------------------------
+
+ @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND id = :id")
+ suspend fun getSeasoningById(id: Long): SeasoningEntity?
+
+ @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND sort = :sort")
+ suspend fun getSeasoningBySort(sort: Int): SeasoningEntity?
+
+ @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsId = :goodsId")
+ suspend fun getSeasoningByGoodsId(goodsId: Int): SeasoningEntity?
+
+ @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsId != -1 AND goodsName != '' ORDER BY sort ASC")
+ fun getAllStream(): Flow>
+
+ @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsName LIKE '%' || :query || '%'")
+ suspend fun search(query: String): MutableList
+
+ @Query("DELETE FROM dm_seasoning WHERE isDel = 0 AND goodsId = -1 AND goodsName = ''")
+ suspend fun deleteEmptySeasoning(): Int
+
+ @Query("DELETE FROM dm_seasoning WHERE isDel = 0")
+ suspend fun deleteBatch(): Int
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insertSeasoningList(items: MutableList): Array
+
+ @Update
+ suspend fun updateSeasoning(item: SeasoningEntity)
+
+ @Insert
+ suspend fun insertSeasoning(item: SeasoningEntity): Long
+ //--------------------------------------------------------------------------------------------
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/db/dao/CookFoodDao.kt b/app/src/main/java/com/shuwei/dish/match/db/dao/CookFoodDao.kt
new file mode 100644
index 0000000..f09e59f
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/db/dao/CookFoodDao.kt
@@ -0,0 +1,20 @@
+//package com.shuwei.dish.match.db.dao
+//
+//import androidx.room.Dao
+//import androidx.room.Query
+//import com.shuwei.dish.match.db.BaseDao
+//import com.shuwei.dish.match.entity.CookFoodEntity
+//
+//@Dao
+//interface CookFoodDao : BaseDao {
+//
+// @Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND foodId = :foodId AND cookMode = :cookMode")
+// suspend fun getCookFoodById(foodId: String, cookMode:Int): CookFoodEntity?
+//
+// @Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND cookMode = :cookMode")
+// suspend fun getCookFoodList(cookMode:Int): MutableList?
+//
+// @Query("SELECT count(1) FROM dm_cook_food WHERE isDel = 0 AND cookMode = :cookMode")
+// suspend fun countCookFood(cookMode:Int): Int
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/db/dao/CookFoodGoodsDao.kt b/app/src/main/java/com/shuwei/dish/match/db/dao/CookFoodGoodsDao.kt
new file mode 100644
index 0000000..cd0b298
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/db/dao/CookFoodGoodsDao.kt
@@ -0,0 +1,29 @@
+//package com.shuwei.dish.match.db.dao
+//
+//import androidx.room.Dao
+//import androidx.room.Query
+//import com.shuwei.dish.match.db.BaseDao
+//import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+//
+//@Dao
+//interface CookFoodGoodsDao : BaseDao {
+//
+// @Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId")
+// suspend fun getCookFoodGoodsList(foodId: String): MutableList
+//
+// @Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId AND materialType = :materialType")
+// suspend fun getCookFoodGoodsListByType(foodId: String, materialType:Int): MutableList
+//
+//// @Query(
+//// """
+//// UPDATE dm_cook_food_goods
+//// SET goodsName=:entity.goodsName, foodId=:entity.foodId, relateionType=:entity.relateionType, sort=:entity.sort
+//// allEdible=:entity.allEdible, useWeight=:entity.useWeight, isDel=:entity.isDel, createTime=:entity.createTime
+//// WHERE isDel = 0
+//// AND foodId=:entity.foodId
+//// AND goodsId=:goodsId
+//// """
+//// )
+//// fun updateByGoodsId(entity: CookFoodGoodsEntity)
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/db/dao/SeasoningDao.kt b/app/src/main/java/com/shuwei/dish/match/db/dao/SeasoningDao.kt
new file mode 100644
index 0000000..105e069
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/db/dao/SeasoningDao.kt
@@ -0,0 +1,25 @@
+//package com.shuwei.dish.match.db.dao
+//
+//import androidx.room.Dao
+//import androidx.room.Query
+//import com.shuwei.dish.match.db.BaseDao
+//import com.shuwei.dish.match.entity.SeasoningEntity
+//import kotlinx.coroutines.flow.Flow
+//
+//@Dao
+//interface SeasoningDao : BaseDao {
+//
+//// @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND id = :id")
+//// suspend fun getSeasoningById(id: Long): SeasoningEntity?
+////
+//// @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 ORDER BY sort ASC")
+//// fun getAllStream(): Flow>
+////
+//// @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND name LIKE '%' || :query || '%'")
+//// suspend fun search(query: String): MutableList
+////
+//// @Query("DELETE FROM dm_seasoning WHERE rowid IN " +
+//// "(SELECT rowid FROM dm_seasoning LIMIT 1000)")
+//// suspend fun deleteBatch(): Int
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/dialog/BottomDialog.kt b/app/src/main/java/com/shuwei/dish/match/dialog/BottomDialog.kt
new file mode 100644
index 0000000..62ed156
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/BottomDialog.kt
@@ -0,0 +1,191 @@
+package com.shuwei.dish.match.dialog
+
+import android.annotation.SuppressLint
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import androidx.core.view.isEmpty
+import androidx.core.widget.addTextChangedListener
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.GoodsInfoSearchAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.databinding.DialogBottomSheetBinding
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.GoodsRecordBean
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.utils.KeyboardUtil
+import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toObject
+import com.shuwei.dish.match.utils.ext.toast
+
+/**
+ * @param goodsType 1-调料,0-食材
+ */
+class BottomDialog(
+ private var goodsType: Int = 1
+) {
+ companion object {
+ const val TAG = "BottomDialog"
+ }
+
+ private var list = mutableListOf()
+
+ private lateinit var binding: DialogBottomSheetBinding
+ private lateinit var goodsInfoSearchAdapter: GoodsInfoSearchAdapter
+ private var goodsName: String? = null
+
+ private var activity: BaseActivity? = null
+
+ fun show(activity: BaseActivity, callback: (item: CookFoodGoodsEntity) -> Unit) {
+ this.activity = activity
+ //直接使用BottomSheetDialog
+ var dialog: BottomSheetDialog? = null
+ val inflater = LayoutInflater.from(activity)
+ binding = DialogBottomSheetBinding.inflate(inflater)
+
+ binding.tvSheetName.text = if (goodsType == 1) "调料检索" else "食材检索"
+ binding.etSheetInput.hint = if (goodsType == 1) "输入调料名称" else "输入食材名称或速记码"
+ goodsInfoSearchAdapter = GoodsInfoSearchAdapter(list).apply {
+ setOnItemClickListener { _, _, position ->
+ list[position].isClicked = true
+ notifyItemChanged(position)
+ Handler(Looper.getMainLooper()).postDelayed({
+ callback(list[position])
+ dialog?.dismiss()
+ }, 300)
+ }
+ }
+ binding.recyclerView.run {
+ layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false)
+ adapter = goodsInfoSearchAdapter
+ addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(rv: RecyclerView, newState: Int) {
+ super.onScrollStateChanged(rv, newState);
+ }
+
+ override fun onScrolled(rv: RecyclerView, dx: Int, dy: Int) {
+ //解决RecyclerView和smartRefreshLayout滑动冲突问题
+ super.onScrolled(rv, dx, dy)
+ val topRowVerticalPosition = if (rv.isEmpty()) 0 else rv.getChildAt(0).top
+ binding.refreshLayout.setNestedScrollingEnabled(topRowVerticalPosition >= 0)
+ }
+ })
+ }
+ dialog = BottomSheetDialog(activity, R.style.BottomSheet).apply {
+ setContentView(binding.root)
+ setCancelable(true)
+ behavior.skipCollapsed = false // 跳过折叠状态
+// behavior.peekHeight = 880.dp
+// window?.setLayout(-1, 880.dp)
+ show()
+ setOnDismissListener {
+ activity.hideStatusBar()
+ }
+ }
+ binding.refreshLayout.setOnRefreshListener {
+ pageNo = 1
+ getGoodsList()
+ }
+
+ binding.refreshLayout.setOnLoadMoreListener {
+ getGoodsList()
+ }
+ binding.etSheetInput.addTextChangedListener(
+ onTextChanged = { text, start, before, count ->
+ goodsName = text.toString()
+ })
+ binding.ivSearch.setOnClickListener { v ->
+ searchGoods(v)
+ }
+ binding.root.setOnClickListener { v ->
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+ binding.etSheetInput.let { v ->
+ v.addOnActionSearchListener {
+ searchGoods(v)
+ }
+ }
+ binding.refreshLayout.setEnableRefresh(false)
+ }
+
+ private fun searchGoods(v: View) {
+ if (goodsName.isNullOrBlank()) {
+ activity?.toast("请${binding.etSheetInput.hint}")
+ return
+ }
+ pageNo = 1
+ getGoodsList()
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+
+ private var pageNo = 1
+ private val pageSize = 120
+
+ /**
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ private fun getGoodsList() {
+// val pathSegmentList = UrlConfig.QUERY_GOODS_LIST.split(delimiters = arrayOf("/"), limit = 1)
+ val queryParams = mutableMapOf(
+ "goodsType" to "$goodsType",
+ "canteenId" to "0",
+ "pageNo" to "$pageNo",
+ "pageSize" to "$pageSize"
+ )
+ if (goodsName.isNullOrBlank().not()) {
+ queryParams.put("name", goodsName!!)
+ }
+ val sb = StringBuilder().apply {
+ append(UrlConfig.QUERY_GOODS_LIST)
+ append("?")
+ queryParams.forEach { (key, value) ->
+ append("$key=$value&")
+ }
+ }
+ sb.deleteCharAt(sb.length - 1)
+ Log.d(TAG, "getGoodsList: url = $sb")
+ HttpUtil.get(
+ url = sb.toString(),
+ doSuccess = {
+ val json = it.toJsonString()
+ Log.d(TAG, "getGoodsList: json=$json")
+ val recordBean: GoodsRecordBean? = json.toObject()
+ if (recordBean == null || recordBean.records.isNullOrEmpty()) {
+ activity?.toast(if (goodsType == 1) "暂未搜索到调料信息" else "暂未搜索到食材信息")
+ return@get
+ }
+ val records = recordBean.records
+ if (pageNo == 1) {
+ list.clear()
+ }
+ list.addAll(records!!)
+ goodsInfoSearchAdapter.notifyDataSetChanged()
+ if (pageNo == 1) {
+ binding.refreshLayout.finishRefresh(1200)
+ } else {
+ binding.refreshLayout.finishLoadMore(1200)
+ }
+ val isLoadMoreEnable = records.size >= pageSize
+ binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
+ if (isLoadMoreEnable) {
+ pageNo++
+ }
+ }, doFailure = { code, msg ->
+ activity?.toast(msg)
+ if (pageNo == 1) {
+ binding.refreshLayout.finishRefresh(1200)
+ } else {
+ binding.refreshLayout.finishLoadMore(1200)
+ }
+ })
+ }
+
+}
+
diff --git a/app/src/main/java/com/shuwei/dish/match/dialog/BottomDialog2.kt b/app/src/main/java/com/shuwei/dish/match/dialog/BottomDialog2.kt
new file mode 100644
index 0000000..466f23a
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/BottomDialog2.kt
@@ -0,0 +1,249 @@
+package com.shuwei.dish.match.dialog
+
+import android.annotation.SuppressLint
+import android.graphics.Typeface
+import android.os.Handler
+import android.os.Looper
+import android.text.SpannableStringBuilder
+import android.text.style.AbsoluteSizeSpan
+import android.text.style.ForegroundColorSpan
+import android.text.style.LineHeightSpan
+import android.text.style.StyleSpan
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import androidx.core.graphics.toColorInt
+import androidx.core.view.isEmpty
+import androidx.core.widget.addTextChangedListener
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.aithings.Weigher
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.SeasoningSearchAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.databinding.DialogBottomSheet2Binding
+import com.shuwei.dish.match.entity.SeasoningEntity
+import com.shuwei.dish.match.entity.SeasoningRecordBean
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.utils.KeyboardUtil
+import com.shuwei.dish.match.utils.WeightUtil
+import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
+import com.shuwei.dish.match.utils.ext.appendText
+import com.shuwei.dish.match.utils.ext.buildSpannableString
+import com.shuwei.dish.match.utils.ext.dp
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toObject
+import com.shuwei.dish.match.utils.ext.toast
+
+/**
+ * @param goodsType 1-调料,0-食材
+ */
+class BottomDialog2(
+ private var weighIndex: Int,
+ private var weighAddress: Int,
+ private var clickName: String? = null
+) {
+ companion object {
+ const val TAG = "BottomDialog"
+ }
+
+ private val goodsType: Int = 1
+ private var list = mutableListOf()
+
+ private lateinit var binding: DialogBottomSheet2Binding
+ private lateinit var searchAdapter: SeasoningSearchAdapter
+ private var goodsName: String? = null
+
+ private var activity: BaseActivity? = null
+
+ fun show(activity: BaseActivity, callback: (item: SeasoningEntity) -> Unit) {
+ this.activity = activity
+ //直接使用BottomSheetDialog
+ var dialog: BottomSheetDialog? = null
+ val inflater = LayoutInflater.from(activity)
+ binding = DialogBottomSheet2Binding.inflate(inflater)
+
+ //binding.tvSheetName.text = if (goodsType == 1) "调料检索" else "食材检索"
+ binding.etSheetInput.hint = if (goodsType == 1) "输入调料名称" else "输入食材名称或速记码"
+ searchAdapter = SeasoningSearchAdapter(list).apply {
+ setOnItemClickListener { _, _, position ->
+ list[position].isClicked = true
+ notifyItemChanged(position)
+ Handler(Looper.getMainLooper()).postDelayed({
+ callback(list[position].also { it.useWeight = currentWeight })
+ dialog?.dismiss()
+ }, 300)
+ }
+ }
+ binding.recyclerView.run {
+ layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false)
+ adapter = searchAdapter
+ addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(rv: RecyclerView, newState: Int) {
+ super.onScrollStateChanged(rv, newState);
+ }
+
+ override fun onScrolled(rv: RecyclerView, dx: Int, dy: Int) {
+ //解决RecyclerView和smartRefreshLayout滑动冲突问题
+ super.onScrolled(rv, dx, dy)
+ val topRowVerticalPosition = if (rv.isEmpty()) 0 else rv.getChildAt(0).top
+ binding.refreshLayout.setNestedScrollingEnabled(topRowVerticalPosition >= 0)
+ }
+ })
+ }
+ dialog = BottomSheetDialog(activity, R.style.BottomSheet).apply {
+ setContentView(binding.root)
+ setCancelable(true)
+ behavior.skipCollapsed = false // 跳过折叠状态
+// behavior.peekHeight = 880.dp
+// window?.setLayout(-1, 880.dp)
+ show()
+ setOnDismissListener {
+ activity.hideStatusBar()
+ }
+ }
+ binding.refreshLayout.setOnRefreshListener {
+ pageNo = 1
+ getGoodsList()
+ }
+
+ binding.refreshLayout.setOnLoadMoreListener {
+ getGoodsList()
+ }
+ binding.etSheetInput.addTextChangedListener(
+ onTextChanged = { text, start, before, count ->
+ goodsName = text.toString()
+ })
+ binding.ivSearch.setOnClickListener { v ->
+ searchGoods(v)
+ }
+ binding.root.setOnClickListener { v ->
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+ binding.etSheetInput.let { v ->
+ v.addOnActionSearchListener {
+ searchGoods(v)
+ }
+ }
+ binding.refreshLayout.setEnableRefresh(false)
+ binding.tvClear.setOnClickListener {
+ Weigher.tareTwo(weighAddress)
+ }
+ WeightUtil.addWeightListener { address, state, weight ->
+ if (weighAddress == address) {
+ this.currentWeight = weight
+ binding.tvWeight.text = getTextSpan(weight)
+ }
+ }
+ binding.tvWeight.text = getTextSpan(0)
+
+ if (clickName.isNullOrBlank().not()) {
+ binding.etSheetInput.setText(clickName!!.trim())
+ pageNo = 1
+ getGoodsList()
+ }
+ }
+
+ private fun searchGoods(v: View) {
+ if (goodsName.isNullOrBlank()) {
+ activity?.toast("请${binding.etSheetInput.hint}")
+ return
+ }
+ pageNo = 1
+ getGoodsList()
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+
+ private var currentWeight = 0
+ private var pageNo = 1
+ private val pageSize = 120
+
+ /**
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ private fun getGoodsList() {
+ val queryParams = mutableMapOf(
+ "goodsType" to "$goodsType",
+ "canteenId" to "0",
+ "pageNo" to "$pageNo",
+ "pageSize" to "$pageSize"
+ )
+ if (goodsName.isNullOrBlank().not()) {
+ queryParams.put("name", goodsName!!)
+ }
+ val sb = StringBuilder().apply {
+ append(UrlConfig.QUERY_GOODS_LIST)
+ append("?")
+ queryParams.forEach { (key, value) ->
+ append("$key=$value&")
+ }
+ }
+ sb.deleteCharAt(sb.length - 1)
+ Log.d(TAG, "getGoodsList: url = $sb")
+ HttpUtil.get(
+ url = sb.toString(),
+ doSuccess = {
+ val json = it.toJsonString()
+ Log.d(TAG, "getGoodsList: json=$json")
+ val recordBean: SeasoningRecordBean? = json.toObject()
+ if (recordBean == null || recordBean.records.isNullOrEmpty()) {
+ activity?.toast(if (goodsType == 1) "暂未搜索到调料信息" else "暂未搜索到食材信息")
+ return@get
+ }
+ val records = recordBean.records
+ if (pageNo == 1) {
+ list.clear()
+ }
+ list.addAll(records!!)
+ searchAdapter.notifyDataSetChanged()
+ if (pageNo == 1) {
+ binding.refreshLayout.finishRefresh(1200)
+ } else {
+ binding.refreshLayout.finishLoadMore(1200)
+ }
+ val isLoadMoreEnable = records.size >= pageSize
+ binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
+ if (isLoadMoreEnable) {
+ pageNo++
+ }
+ }, doFailure = { code, msg ->
+ activity?.toast(msg)
+ if (pageNo == 1) {
+ binding.refreshLayout.finishRefresh(1200)
+ } else {
+ binding.refreshLayout.finishLoadMore(1200)
+ }
+ })
+ }
+
+ fun getTextSpan(weight: Int): SpannableStringBuilder {
+ var topWeight = "$weight"
+ var bottomUnit = "克"
+ if (weight >= 1000) {
+ topWeight = "${weight / 1000F}"
+ bottomUnit = "千克"
+ }
+ return buildSpannableString {
+ appendText(
+ topWeight,
+ ForegroundColorSpan("#000000".toColorInt()),
+ StyleSpan(Typeface.BOLD),
+ AbsoluteSizeSpan(72, true),
+ LineHeightSpan { text, start, end, spanstartv, v, fm ->
+ fm.descent += 10.dp // 增加行间距
+ }
+ )
+ append("\n")
+ appendText(
+ bottomUnit,
+ ForegroundColorSpan("#999999".toColorInt()),
+ AbsoluteSizeSpan(30, true)
+ )
+ }
+ }
+}
+
+
+
diff --git a/app/src/main/java/com/shuwei/dish/match/dialog/CommonDialog.kt b/app/src/main/java/com/shuwei/dish/match/dialog/CommonDialog.kt
new file mode 100644
index 0000000..4700fe5
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/CommonDialog.kt
@@ -0,0 +1,80 @@
+package com.shuwei.dish.match.dialog
+
+import android.app.Activity
+import android.app.Dialog
+import android.graphics.drawable.ColorDrawable
+import android.os.Bundle
+import android.view.View
+import android.view.Window
+import android.view.WindowManager
+import androidx.annotation.StyleRes
+import androidx.fragment.app.FragmentActivity
+import com.shuwei.dish.match.databinding.DialogCommonBinding
+import com.shuwei.dish.match.utils.ext.dp
+import java.lang.ref.WeakReference
+
+open class CommonDialog(
+ private var activity: FragmentActivity
+) : Dialog(activity) {
+
+ private lateinit var binding: DialogCommonBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ requestWindowFeature(Window.FEATURE_NO_TITLE)
+ binding = DialogCommonBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ window?.run {
+// decorView.setPadding(0.dp, 0, 0.dp, 0)
+ attributes = attributes.apply {
+ width = 708.dp
+ }
+ setBackgroundDrawable(ColorDrawable())
+ setCancelable(false)
+// setFlags(
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+// )
+ }
+
+ binding.llContent.run {
+ removeAllViews()
+ addView(messageView)
+ }
+ addListener()
+ }
+
+ private fun addListener() {
+ binding.btnLeft.setOnClickListener { onLeftClick?.invoke() }
+ binding.btnRight.setOnClickListener { onRightClick?.invoke() }
+ setOnDismissListener { onDismiss?.invoke() }
+ }
+
+
+ override fun show() {
+ super.show()
+ binding.btnLeft.text = leftText
+ binding.btnRight.text = rightText
+ }
+
+ var messageView: View? = null
+ var onLeftClick: (() -> Unit)? = null
+ var onRightClick: (() -> Unit)? = null
+
+ var leftText = ""
+ var rightText = ""
+
+ var onDismiss: (() -> Unit)? = null
+
+}
+
+open class SafeDialog(activity: Activity, @StyleRes themeResId: Int) :
+ Dialog(activity, themeResId) {
+ private val weakContext = WeakReference(activity)
+
+ override fun show() {
+ weakContext.get()?.let {
+ if (!it.isFinishing && !it.isDestroyed) super.show()
+ }
+ }
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/dialog/CustomToast.kt b/app/src/main/java/com/shuwei/dish/match/dialog/CustomToast.kt
new file mode 100644
index 0000000..a46a346
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/CustomToast.kt
@@ -0,0 +1,136 @@
+//package com.shuwei.dish.match.dialog
+//
+//import android.app.Activity
+//import android.graphics.Color
+//import android.os.Bundle
+//import android.util.TypedValue
+//import android.view.Gravity
+//import android.view.WindowManager
+//import android.widget.TextView
+//import androidx.core.graphics.drawable.toDrawable
+//import com.shuwei.dish.match.R
+//
+//class CustomToast(
+// private val activity: Activity,
+// private val message: String?,
+// private val duration: Int = 2000
+//) :
+// SafeDialog(
+// activity = activity,
+// themeResId = R.style.ToastDialogTheme,
+// ) {
+//
+// override fun onCreate(savedInstanceState: Bundle?) {
+// super.onCreate(savedInstanceState)
+// setContentView(R.layout.custom_toast)
+// findViewById(R.id.tvMessage)?.text = message
+// setCancelable(true)
+// if (message.isNullOrBlank() ||
+// duration <= 0 ||
+// activity.isDestroyed ||
+// activity.isFinishing
+// ) {
+// return
+// }
+// window?.run {
+// setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
+// setDimAmount(0f)
+// setGravity(Gravity.BOTTOM)
+// val metrics = activity.resources.displayMetrics
+// val marginPx = TypedValue.applyDimension(
+// TypedValue.COMPLEX_UNIT_DIP,
+// 120f,
+// metrics
+// )
+// attributes = attributes?.apply {
+// y = marginPx.toInt() // 直接设置像素值
+// }
+// setFlags(
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+// )
+// }
+// }
+//
+// override fun show() {
+// runCatching {
+// super.show()
+// window?.decorView?.postDelayed({
+// if (message.isNullOrBlank() || activity.isDestroyed || activity.isFinishing) {
+// return@postDelayed
+// }
+// super.dismiss()
+// }, duration.toLong())
+// }.onFailure {
+// it.printStackTrace()
+// }
+// }
+//
+// override fun dismiss() {
+// runCatching {
+// super.dismiss()
+// }.onFailure {
+// it.printStackTrace()
+// }
+// }
+//
+//}
+//
+////class CustomToast2(
+//// private val activity: Activity,
+//// private val message: String?,
+//// private val duration: Int = 2000
+////) :
+//// DialogFragment() {
+////
+//// override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+//// return SafeDialog(
+//// activity = activity,
+//// themeResId = R.style.ToastDialogTheme,
+//// ).apply {
+//// setContentView(R.layout.custom_toast)
+//// findViewById(R.id.tvMessage)?.text = message
+//// setCancelable(true)
+//// if (message.isNullOrBlank() ||
+//// duration <= 0 ||
+//// activity.isDestroyed ||
+//// activity.isFinishing
+//// ) {
+//// return@apply
+//// }
+//// window?.run {
+//// setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
+//// setDimAmount(0f)
+//// setGravity(Gravity.BOTTOM)
+//// val metrics = activity.resources.displayMetrics
+//// val marginPx = TypedValue.applyDimension(
+//// TypedValue.COMPLEX_UNIT_DIP,
+//// 120f,
+//// metrics
+//// )
+//// attributes = attributes?.apply {
+//// y = marginPx.toInt() // 直接设置像素值
+//// }
+//// setFlags(
+//// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+//// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+//// )
+//// }
+//// }
+//// }
+////
+//// override fun show(manager: FragmentManager, tag: String?) {
+//// runCatching {
+//// super.show(manager, tag)
+//// Handler(Looper.getMainLooper()).postDelayed({
+//// if (message.isNullOrBlank() || activity.isDestroyed || activity.isFinishing) {
+//// return@postDelayed
+//// }
+//// dismiss()
+//// }, duration.toLong())
+//// }.onFailure {
+//// it.printStackTrace()
+//// }
+//// }
+////
+////}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/dialog/DialogTool.kt b/app/src/main/java/com/shuwei/dish/match/dialog/DialogTool.kt
new file mode 100644
index 0000000..4ea6284
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/DialogTool.kt
@@ -0,0 +1,26 @@
+//package com.shuwei.dish.match.dialog
+//
+//import android.content.Context
+//import android.view.LayoutInflater
+//import androidx.fragment.app.FragmentActivity
+//import com.shuwei.dish.match.databinding.LayoutFoodRemindBinding
+//
+//object DialogTool {
+//
+// fun load(activity: FragmentActivity, leftText:) {
+// val layoutInflater = LayoutInflater.from(activity)
+// val remindBinding = LayoutFoodRemindBinding.inflate(layoutInflater)
+// CommonDialog(activity).apply {
+// messageView = remindBinding.root
+// leftText = "返回调整"
+// rightText = "确认无误"
+// onLeftClick = { dismiss() }
+// onRightClick = {
+// goToSubmit()
+// dismiss()
+// }
+// onDismiss = { hideStatusBar() }
+// }.show()
+// }
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/dialog/LoadingDialog.kt b/app/src/main/java/com/shuwei/dish/match/dialog/LoadingDialog.kt
new file mode 100644
index 0000000..83fa748
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/LoadingDialog.kt
@@ -0,0 +1,140 @@
+package com.shuwei.dish.match.dialog
+
+import android.app.Dialog
+import android.content.Context
+import android.graphics.Color
+import android.view.LayoutInflater
+import android.view.WindowManager
+import androidx.core.graphics.drawable.toDrawable
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.DialogLoadingBinding
+
+object Loading {
+
+ private var dialog: LoadingDialog? = null
+
+ fun show(context: Context) {
+ if (dialog?.isShowing == true) {
+ dialog?.dismiss()
+ }
+
+ if (dialog == null) {
+ dialog = LoadingDialog(context)
+ }
+ dialog?.show()
+ }
+
+ fun dismiss() {
+ dialog?.let {
+ if (it.isShowing) {
+ it.dismiss()
+ }
+ }
+ dialog = null
+ }
+
+}
+
+class LoadingDialog(
+ context: Context,
+ message: String = "加载中……",
+ private var onDismiss: () -> Unit = {}
+) : Dialog(context, R.style.LoadingDialog) {
+ init {
+ val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context))
+ binding.tvMessage.text = message
+ setContentView(binding.root)
+ setCancelable(true)
+ window?.run {
+ setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
+ setFlags(
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ );
+ }
+ setOnDismissListener {
+ onDismiss()
+ }
+ }
+}
+
+//class LoadingDialog3(
+// private val activity: Activity,
+// private val message: String = "加载中……",
+// private val onDismiss: () -> Unit = {}
+//) : DialogFragment() {
+//
+// override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+// return SafeDialog(
+// activity = activity,
+// themeResId = R.style.ToastDialogTheme,
+// ).apply {
+// val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context))
+// binding.tvMessage.text = message
+// setContentView(binding.root)
+// setCancelable(true)
+// window?.run {
+// setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
+// setFlags(
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+// );
+// }
+// setOnDismissListener {
+// onDismiss()
+// }
+// }
+// }
+//
+// override fun dismiss() {
+// super.dismiss()
+// }
+//
+// override fun show(manager: FragmentManager, tag: String?) {
+// runCatching {
+// super.show(manager, tag)
+// Handler(Looper.getMainLooper()).postDelayed({
+// super.dismiss()
+// }, 800)
+// }.onFailure {
+// it.printStackTrace()
+// }
+// }
+//
+//}
+
+//class LoadingDialog(
+// private val activity: Activity,
+// private val message: String = "加载中……",
+// private val onDismiss: () -> Unit = {}
+//) : SafeDialog(
+// activity = activity,
+// themeResId = R.style.ToastDialogTheme,
+//) {
+//
+// override fun onCreate(savedInstanceState: Bundle?) {
+// super.onCreate(savedInstanceState)
+// val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context))
+// binding.tvMessage.text = message
+// setContentView(binding.root)
+// setCancelable(true)
+// window?.run {
+// setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
+// setFlags(
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+// );
+// }
+// setOnDismissListener {
+// onDismiss()
+// }
+// }
+//
+// fun show(manager: FragmentManager, tag: String?) {
+// show()
+// Handler(Looper.getMainLooper()).postDelayed({
+// super.dismiss()
+// }, 800)
+// }
+//
+//}
diff --git a/app/src/main/java/com/shuwei/dish/match/entity/CookFoodEntity.kt b/app/src/main/java/com/shuwei/dish/match/entity/CookFoodEntity.kt
new file mode 100644
index 0000000..10faac6
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/entity/CookFoodEntity.kt
@@ -0,0 +1,26 @@
+package com.shuwei.dish.match.entity
+
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.PrimaryKey
+import com.shuwei.dish.match.db.BaseEntity
+import com.shuwei.dish.match.utils.DateTimeUtil
+import java.time.LocalDateTime
+
+@Entity(tableName = "dm_cook_food")
+data class CookFoodEntity(
+ @PrimaryKey
+ var foodId: String,
+ var foodName: String? = null,
+ var canteenId: Int? = null,
+ var foodWeight: Int = 0,
+ //0-制作模式,1-采样模式,2-品控模式
+ var cookMode:Int = 0,
+ var isDel: Int = 0,
+ var createTime: String = DateTimeUtil.formatDateTime(LocalDateTime.now()),
+) : BaseEntity {
+ @Ignore
+ var stFoodInfoConstituteList: MutableList? = null
+
+ constructor() : this(foodId = "") // 必需的空构造
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/entity/CookFoodGoodsEntity.kt b/app/src/main/java/com/shuwei/dish/match/entity/CookFoodGoodsEntity.kt
new file mode 100644
index 0000000..8453788
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/entity/CookFoodGoodsEntity.kt
@@ -0,0 +1,76 @@
+package com.shuwei.dish.match.entity
+
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.PrimaryKey
+import com.shuwei.dish.match.db.BaseEntity
+import com.shuwei.dish.match.utils.DateTimeUtil
+import java.io.Serializable
+import java.time.LocalDateTime
+
+@Entity(tableName = "dm_cook_food_goods")
+class CookFoodGoodsEntity(
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0,
+ /**
+ * 物品id
+ */
+ var goodsId: Int,
+
+ /**
+ * 物品名称
+ */
+ var goodsName: String? = null,
+
+ /**
+ * 菜品id
+ */
+ var foodId: String? = "",
+ var goodsOrRelationCode: String? = "",
+ /**
+ * 调料数据顺序
+ */
+ var sort: Int = 0,
+
+ /**
+ * 食材原材料:1,预制品:2
+ */
+ var relateionType: Int = 0,
+ /**
+ * 物品类型:1主料2辅料3调料
+ */
+ var materialType: Int = 0,
+
+ /**
+ * 物品 是否全部可食:1-全部可食,0-部分可食,默认全部
+ */
+ var allEdible: Int = 1,
+
+ /**
+ * 物品 用料重量
+ */
+ var useWeight: Int? = 0,
+
+ var popularName: String? = "",
+
+ var canteenId: String? = "",
+
+ var relateionType_dictText: String? = "",
+
+ var isDel: Int = 0,
+ var createTime: String = DateTimeUtil.formatDateTime(LocalDateTime.now())
+) : BaseEntity, Serializable {
+ constructor() : this(goodsId = -1) // 必需的空构造,
+
+ @Ignore
+ var isSetFinished: Boolean = false
+ @Ignore
+ var isItemClicked: Boolean = false
+ @Ignore
+ var isSamplingPage: Boolean = false
+ @Ignore
+ var isNewDishType: Boolean = false
+
+ @Ignore
+ var isClicked: Boolean = false
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/entity/DataBean.kt b/app/src/main/java/com/shuwei/dish/match/entity/DataBean.kt
new file mode 100644
index 0000000..2093179
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/entity/DataBean.kt
@@ -0,0 +1,58 @@
+package com.shuwei.dish.match.entity
+
+data class HomeModeBean(
+
+ var modeName: String = "",
+ var modeDesc: String = "",
+ var modeIconId: Int = 0,
+ var isLocked: Boolean = false,
+
+ var onClick: (() -> Unit)? = null
+)
+
+data class FoodRecordBean(
+ var records: MutableList? = null,
+ var total: Int,
+ var size: Int,
+ var current: Int,
+ var page: Int
+)
+
+data class GoodsRecordBean(
+ var records: MutableList? = null,
+ var total: Int,
+ var size: Int,
+ var current: Int,
+ var page: Int
+)
+
+data class SeasoningRecordBean(
+ var records: MutableList? = null,
+ var total: Int,
+ var size: Int,
+ var current: Int,
+ var page: Int
+)
+
+//data class DishDetailEntity(
+// var foodId: String? = null,
+// var foodWeight: Double? = null,
+// var foodRealWeight: Double? = null,
+// var voList: List? = null
+//)
+
+//data class DishPartEntity(
+// var foodId: String? = null,
+// var foodName: String? = null,
+// var foodWeight: Int? = null,
+// var useWeight: Int? = null,
+// var useRealWeight: Int? = null,
+// var goodsId: Int? = null,
+// var goodsName: String? = null,
+// var materialType: Int? = null,
+// var isSetFinished: Boolean = false,
+// var isItemClicked: Boolean = false,
+// var isSamplingPage: Boolean = false
+//)
+
+
diff --git a/app/src/main/java/com/shuwei/dish/match/entity/DishEntity.kt b/app/src/main/java/com/shuwei/dish/match/entity/DishEntity.kt
new file mode 100644
index 0000000..0c7c247
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/entity/DishEntity.kt
@@ -0,0 +1,25 @@
+package com.shuwei.dish.match.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import com.shuwei.dish.match.db.BaseEntity
+
+//@Entity(tableName = "dm_dish")
+//data class DishEntity (
+// /**
+// * 菜品id
+// */
+// @PrimaryKey var id: Long,
+// /**
+// * 菜品名称
+// */
+// var name: String? = "",
+// /**
+// * 菜品重量
+// */
+// var weight: Int? = 0,
+//
+// var sort: Int = 0,
+// @ColumnInfo(name = "create_time") val createTime: Long = System.currentTimeMillis()
+//): BaseEntity
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/entity/FoodRecord.kt b/app/src/main/java/com/shuwei/dish/match/entity/FoodRecord.kt
new file mode 100644
index 0000000..9fd19dc
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/entity/FoodRecord.kt
@@ -0,0 +1,17 @@
+package com.shuwei.dish.match.entity
+
+import java.io.Serializable
+
+data class FoodRecord(
+ var foodId: String? = null,
+ var foodName: String? = null,
+ var foodWeight: Int? = null,
+ var totalWeight: Int? = null,
+ var count: Int? = null,
+ var isCooking: Boolean = false,
+ //0-制作模式,1-采样模式,2-品控模式
+ var cookMode: Int = 0,
+
+ var sort: Int = 0
+) : Serializable
+
diff --git a/app/src/main/java/com/shuwei/dish/match/entity/GoodsInfoEntity.kt b/app/src/main/java/com/shuwei/dish/match/entity/GoodsInfoEntity.kt
new file mode 100644
index 0000000..20c2816
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/entity/GoodsInfoEntity.kt
@@ -0,0 +1,38 @@
+//package com.shuwei.dish.match.entity
+//
+//import androidx.room.Ignore
+//import androidx.room.PrimaryKey
+//import com.shuwei.dish.match.db.BaseEntity
+//
+//data class GoodsInfoEntity(
+// @PrimaryKey(autoGenerate = true) var id: Long = 0,
+// var goodsId: Int,
+// var goodsName: String? = "",
+// var popularName: String? = "",
+// var canteenId: String? = "",
+// var goodsOrRelationCode: String? = "",
+// var relateionType: Int? = -1,
+// var relateionType_dictText: String? = "",
+//
+// var sort: Int = 0,
+//
+// var swMaterBaseMaterial: String? = "",
+// var preMaterClass: String? = "",
+// var preUseWeight: Int? = 0,
+// var preWeight: Int? = 0,
+// var oil: String? = "",
+// var sugar: String? = "",
+// /**
+// * isDel表示数据是否已删除,1-已删除,为无效数据,0-正常使用,有效数据
+// */
+// var isDel: Int = 0,
+// val createTime: Long = System.currentTimeMillis()
+//) : BaseEntity {
+// @Ignore
+// var pageType: Int = 0
+//
+// @Ignore
+// var isClicked: Boolean = false
+//
+// constructor() : this(id = -1, goodsId = -1) // 必需的空构造
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/entity/SeasoningEntity.kt b/app/src/main/java/com/shuwei/dish/match/entity/SeasoningEntity.kt
new file mode 100644
index 0000000..1c60145
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/entity/SeasoningEntity.kt
@@ -0,0 +1,69 @@
+package com.shuwei.dish.match.entity
+
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.PrimaryKey
+import com.shuwei.dish.match.db.BaseEntity
+import com.shuwei.dish.match.utils.DateTimeUtil
+import java.time.LocalDateTime
+
+@Entity(tableName = "dm_seasoning")
+data class SeasoningEntity(
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0,
+ /**
+ * 物品id
+ */
+ var goodsId: Int,
+
+ /**
+ * 物品名称
+ */
+ var goodsName: String? = null,
+
+ /**
+ * 菜品id
+ */
+ var foodId: String? = "",
+ var goodsOrRelationCode: String? = "",
+
+ /**
+ * 食材原材料:1,预制品:2
+ */
+ var relateionType: Int = 0,
+ /**
+ * 物品类型:1主料2辅料3调料
+ */
+ var materialType: Int = 3,
+
+ /**
+ * 物品 是否全部可食:1-全部可食,0-部分可食,默认全部
+ */
+ var allEdible: Int = 1,
+
+ /**
+ * 物品 用料重量
+ */
+ var useWeight: Int? = 0,
+
+ var popularName: String? = "",
+
+ var canteenId: String? = "",
+
+ var relateionType_dictText: String? = "",
+
+ var sort: Int = 9999,
+ /**
+ * isDel表示数据是否已删除,1-已删除,为无效数据,0-正常使用,有效数据
+ */
+ var isDel: Int = 0,
+ var createTime: String = DateTimeUtil.formatDateTime(LocalDateTime.now())
+) : BaseEntity {
+ @Ignore
+ var pageType: Int = 0
+
+ @Ignore
+ var isClicked: Boolean = false
+
+ constructor() : this(goodsId = -1) // 必需的空构造
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/http/HttpClient.kt b/app/src/main/java/com/shuwei/dish/match/http/HttpClient.kt
new file mode 100644
index 0000000..c46521d
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/http/HttpClient.kt
@@ -0,0 +1,70 @@
+package com.shuwei.dish.match.http
+
+import android.annotation.SuppressLint
+import android.util.Log
+import okhttp3.Call
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import java.util.concurrent.TimeUnit
+
+import javax.net.ssl.*
+import java.security.SecureRandom
+import java.security.cert.X509Certificate
+
+class HttpClient private constructor() {
+ private val client: OkHttpClient by lazy {
+ OkHttpClient.Builder()
+ .apply {
+ connectTimeout(15, TimeUnit.SECONDS)
+ readTimeout(30, TimeUnit.SECONDS)
+ writeTimeout(15, TimeUnit.SECONDS)
+ sslSocketFactory(createSSLSocketFactory(), TrustAllCerts())
+ hostnameVerifier { _, _ -> true }
+ //if (BuildConfig.Debug) {
+ addInterceptor(LoggingInterceptor())
+ // }
+ }
+ .build()
+ }
+
+ companion object {
+ val instance by lazy { HttpClient() }
+ }
+
+ fun newCall(request: Request): Call = client.newCall(request)
+
+ inner class LoggingInterceptor : Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val request = chain.request()
+ // 打印请求日志
+ Log.d("OkHttp", "--> ${request.method} ${request.url}")
+
+ val response = chain.proceed(request)
+ // 打印响应日志
+ Log.d("OkHttp", "<-- ${response.code} ${response.request.url}")
+
+ return response
+ }
+ }
+
+ // 信任所有证书的TrustManager实现
+ @SuppressLint("CustomX509TrustManager")
+ class TrustAllCerts : X509TrustManager {
+ @SuppressLint("TrustAllX509TrustManager")
+ override fun checkClientTrusted(chain: Array, authType: String) {}
+ @SuppressLint("TrustAllX509TrustManager")
+ override fun checkServerTrusted(chain: Array, authType: String) {}
+ override fun getAcceptedIssuers(): Array = arrayOf()
+ }
+
+ // 创建信任所有证书的SSLSocketFactory
+ fun createSSLSocketFactory(): SSLSocketFactory {
+ val sslContext = SSLContext.getInstance("TLS").apply {
+ init(null, arrayOf(TrustAllCerts()), SecureRandom())
+ }
+ return sslContext.socketFactory
+ }
+
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/http/HttpUtil.kt b/app/src/main/java/com/shuwei/dish/match/http/HttpUtil.kt
new file mode 100644
index 0000000..381c296
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/http/HttpUtil.kt
@@ -0,0 +1,166 @@
+package com.shuwei.dish.match.http
+
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import com.google.gson.reflect.TypeToken
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.base.BaseReq
+import com.shuwei.dish.match.http.HttpUtil.runMainThread
+import com.shuwei.dish.match.utils.ext.put
+import com.shuwei.dish.match.utils.ext.toType
+import com.shuwei.dish.match.utils.ext.toast
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.HttpUrl
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import okhttp3.Response
+import java.io.IOException
+
+
+object HttpUtil {
+
+ fun runMainThread(action: () -> Unit) {
+ Handler(Looper.getMainLooper()).post {
+ action()
+ }
+ }
+
+ // GET请求(HTTPS)
+ fun get(
+ url: String,
+ doSuccess: (data: Any) -> Unit,
+ doFailure: (code: Int?, msg: String?) -> Unit
+ ) {
+ val token = getToken()
+ val request = Request.Builder()
+ .url(url)
+ .apply {
+ if (token.isNotBlank()) {
+ addHeader("X-Access-Token", token)
+ }
+ }
+ .get()
+ .build()
+ HttpClient.instance.newCall(request).enqueue(CallbackImpl(doSuccess, doFailure))
+ }
+
+ fun get(
+ isHttps: Boolean = false,
+ host: String = "vip.shuziweidao.com",
+ pathSegmentList: List,
+ queryParams: Map,
+ doSuccess: (data: Any) -> Unit,
+ doFailure: (code: Int?, msg: String?) -> Unit
+ ) {
+ val token = getToken()
+ val url = HttpUrl.Builder()
+ .scheme(if (isHttps) "https" else "http")
+ .host(host)
+ .apply {
+ pathSegmentList.forEach { addPathSegment(it) }
+ queryParams.forEach { (key, value) -> addQueryParameter(key, value) }
+ }
+ .build()
+ val request = Request.Builder()
+ .url(url)
+ .apply {
+ if (token.isNotBlank()) {
+ addHeader("Authorization", token)
+ }
+ }
+ .get()
+ .build()
+ HttpClient.instance.newCall(request).enqueue(CallbackImpl(doSuccess, doFailure))
+ }
+
+ // POST表单(HTTPS)
+// fun postForm(url: String, params: Map, callback: Callback) {
+// val formBody = FormBody.Builder().apply {
+// params.forEach { (k, v) -> add(k, v) }
+// }.build()
+//
+// Request.Builder()
+// .url(url)
+// .post(formBody)
+// .build().let { HttpClient.instance.newCall(it).enqueue(callback) }
+// }
+
+ // POST JSON(HTTPS)
+ fun postJson(
+ url: String,
+ json: String,
+ doSuccess: (data: Any) -> Unit,
+ doFailure: (code: Int?, msg: String?) -> Unit
+ ) {
+ val body = json
+ .toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
+ val token = getToken()
+ Request.Builder()
+ .url(url)
+ .apply {
+ if (token.isNotBlank()) {
+ addHeader("X-Access-Token", token)
+ }
+ }
+ .post(body)
+ .build()
+ .let { HttpClient.instance.newCall(it).enqueue(CallbackImpl(doSuccess, doFailure)) }
+ }
+
+}
+
+class CallbackImpl(
+ private val doSuccess: (data: Any) -> Unit,
+ private val doFailure: (code: Int?, msg: String?) -> Unit
+) :
+ Callback {
+ override fun onFailure(call: Call, e: IOException) {
+ runMainThread {
+ e.printStackTrace()
+ doFailure(-1, "服务异常,${e.message}")
+ }
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ val respData = response.body?.string()
+ runMainThread {
+ Log.d("HttpUtil", respData ?: "")
+ runCatching {
+ val typeToken = object : TypeToken>() {}
+ val baseReq = respData?.toType>(typeToken = typeToken)
+ if (baseReq == null) {
+ doFailure(-1, "查询数据失败")
+ return@runCatching
+ }
+ if (baseReq.code != 200) {
+ doFailure(baseReq.code, baseReq.message)
+ if (baseReq.code == 500 || baseReq.code == 401) {
+ getAppToken()
+ }
+ return@runCatching
+ }
+ doSuccess(baseReq.result ?: "")
+ }.onFailure {
+ it.printStackTrace()
+ doFailure(-1, "解析异常")
+ }
+ }
+ }
+}
+
+private fun getToken() = BaseApp.instance?.token ?:""
+//BaseApp.getSharedPref()?.getString("token", "") ?: ""
+
+private fun getAppToken() {
+ val url = "${UrlConfig.GET_TOKEN}?qrcodeId=${BaseApp.instance?.androidId}"
+// Log.d(TAG, "getToken: url = $url")
+ HttpUtil.get(url = url, doSuccess = {
+ BaseApp.getSharedPref()?.put("token" to it)
+ BaseApp.instance?.token = it.toString()
+ }) { code, msg ->
+ //toast(msg)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/http/UrlConfig.kt b/app/src/main/java/com/shuwei/dish/match/http/UrlConfig.kt
new file mode 100644
index 0000000..755b9be
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/http/UrlConfig.kt
@@ -0,0 +1,23 @@
+package com.shuwei.dish.match.http
+
+object UrlConfig {
+
+// const val BASE_URL = "http://vip.shuziweidao.com/shuwei-zhct"
+// const val DISH_DETAIL = "$BASE_URL/scales/goodsUseList?foodId={foodId}&foodWeight={foodWeight}"
+// const val DISH_LIST = "$BASE_URL/scales/getRestInfoFoods?eaId=99&type=0&foodName"
+
+ const val BASE_URL = "http://192.168.1.207:9102"
+// const val DISH_LIST = "$BASE_URL/scales/getRestInfoFoods?eaId=99&type=0&foodName"
+
+ const val DISH_DETAIL = "$BASE_URL/food/stFoodInfoMatching/queryById"
+
+ // "$BASE_URL/scales/generateToken?deviceId=1111111111111111111111111111"
+
+ const val GET_TOKEN = "$BASE_URL/restaurant/equipment/stEquipment/getEquipmentToken"
+ const val SUBMIT_DISH = "$BASE_URL/food/stFoodInfoMatching/saveoredit"
+
+ const val QUERY_GOODS_LIST = "$BASE_URL/food/stFoodInfoMatching/queryGoodsInfoList"
+ const val QUERY_FOOD_LIST = "$BASE_URL/food/stFoodInfoMatching/list"
+ const val SAMPLING_LIST = "$BASE_URL/food/stFoodInfoMatching/queryHistorical/goodsInfoList"
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/DeviceSettingActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/DeviceSettingActivity.kt
new file mode 100644
index 0000000..4db04d0
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/DeviceSettingActivity.kt
@@ -0,0 +1,265 @@
+package com.shuwei.dish.match.ui
+
+import android.graphics.Typeface
+import android.os.Bundle
+import android.text.SpannableStringBuilder
+import android.text.style.AbsoluteSizeSpan
+import android.text.style.ForegroundColorSpan
+import android.text.style.LineHeightSpan
+import android.text.style.StyleSpan
+import android.util.Log
+import androidx.core.graphics.toColorInt
+import androidx.lifecycle.ViewModelProvider
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.SeasoningCellTool
+import com.shuwei.dish.match.adapter.TextCellAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.databinding.ActivityDeviceSettingBinding
+import com.shuwei.dish.match.db.AppRepository
+
+import com.shuwei.dish.match.entity.SeasoningEntity
+import com.shuwei.dish.match.utils.ext.appendText
+import com.shuwei.dish.match.utils.ext.buildSpannableString
+import com.shuwei.dish.match.utils.ext.dp
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+import com.shuwei.dish.match.viewmodel.AppViewModel
+import com.shuwei.dish.match.viewmodel.factory.AppFactory
+
+class DeviceSettingActivity : BaseActivity() {
+
+ companion object {
+
+ const val TAG = "DeviceSettingActivity"
+
+ const val COOK_MODE = "cookMode"
+
+ val modeList = listOf(
+ ModeBean("制作模式", "菜品快速制作,记录熟重"),
+ ModeBean("采样模式", "菜品快速制作,记录熟重"),
+ ModeBean("品控模式", "菜品快速制作,记录熟重")
+ )
+ }
+
+ data class ModeBean(
+ var modeName: String,
+ var modeDesc: String
+ )
+
+ private lateinit var binding: ActivityDeviceSettingBinding
+
+ private lateinit var appViewModel: AppViewModel
+
+// public lateinit var list: MutableList
+
+ private var cookMode: Int = 0
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityDeviceSettingBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ cookMode = intent.getIntExtra(COOK_MODE, 0)
+ initViewModel()
+ setHeaderBackground()
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "设备配置"
+ })
+
+ addListener()
+
+ loadQualitySpan(isEnable = false)
+ when (cookMode) {
+ 1 -> {
+ binding.rbModeCook.isChecked = true
+ binding.rbModeSampling.isChecked = false
+ loadCookSpan(isClicked = true)
+ loadSamplingSpan()
+ }
+ 2 -> {
+ binding.rbModeCook.isChecked = false
+ binding.rbModeSampling.isChecked = true
+ loadCookSpan()
+ loadSamplingSpan(isClicked = true)
+ }
+ else -> 0
+ }
+
+ binding.rbModeCook.setOnClickListener {
+ binding.rbModeCook.isChecked = true
+ binding.rbModeSampling.isChecked = false
+ loadCookSpan(isClicked = true)
+ loadSamplingSpan()
+ startActivity { }
+ finish()
+ }
+ binding.rbModeSampling.setOnClickListener {
+ binding.rbModeCook.isChecked = false
+ binding.rbModeSampling.isChecked = true
+ loadCookSpan()
+ loadSamplingSpan(isClicked = true)
+ startActivity { }
+ finish()
+ }
+ }
+
+ private fun initViewModel() {
+ val db = BaseApp.instance!!.database
+ val factory =
+ AppFactory(AppRepository(db.appDao()))
+ appViewModel =
+ ViewModelProvider(this, factory)[AppViewModel::class.java]
+ }
+
+ override fun onResume() {
+ super.onResume()
+ appViewModel.loadSeasoning { it ->
+ SeasoningCellTool.loadData(
+ activity = this,
+ initList = it,
+ recyclerView = binding.rvSeasoning,
+ tvCell = binding.tvRightBottomCell,
+ pageType = 1
+ )
+// (binding.rvSeasoning.adapter as TextCellAdapter).let { adapter ->
+// list = adapter.list
+// }
+ }
+ }
+
+// private var isCookMode: Boolean = true
+
+ private fun addListener() {
+// binding.modeRadioGroup.setOnCheckedChangeListener { _, checkedId ->
+// when (checkedId) {
+// R.id.rbModeCook -> {
+// isCookMode = true
+// loadCookSpan(isClicked = true)
+// loadSamplingSpan()
+// loadQualitySpan(isEnable = false)
+// }
+//
+// R.id.rbModeSampling -> {
+// isCookMode = false
+// loadCookSpan()
+// loadSamplingSpan(isClicked = true)
+// loadQualitySpan(isEnable = false)
+// }
+//
+// R.id.rbModeQuality -> {
+// loadCookSpan()
+// loadSamplingSpan()
+// loadQualitySpan(isEnable = false)
+// }
+// }
+// }
+// binding.btnCancel.setOnClickListener { finish() }
+// binding.btnConfirm.setOnClickListener { confirmSetting() }
+
+ }
+
+ private fun confirmSetting() {
+// runCatching {
+// showLoading()
+//// list.forEachIndexed { index, entity ->
+//// entity.sort = index
+//// }
+//// val list2 = mutableListOf()
+//// list2.addAll(list)
+//// val array = arrayOf(10, 11, 13)
+//// list.forEachIndexed { index, entity ->
+//// if (entity.sort == 14 && array.contains(index)) {
+//// list2.remove(entity)
+//// }
+//// }
+// Log.d(TAG, "addListener->Click: ${list.toJsonString()}")
+//
+// appViewModel.addSeasoning(list) {
+// dismissLoading()
+// if (isCookMode) {
+// startActivity { }
+// } else {
+// startActivity { }
+// }
+//// val activityStack = ActivityManager.getActivityStack()
+//// activityStack.forEach {
+//// if (it !is SelectDishActivity && it !is SamplingListActivity) {
+//// it.finish()
+//// }
+//// }
+// }
+// }.onFailure {
+// it.printStackTrace()
+// toast("数据提交失败")
+// }
+ }
+
+
+ private fun loadQualitySpan(isClicked: Boolean = false, isEnable: Boolean = true) {
+ binding.rbModeQuality.text =
+ getModeTextSpan(
+ topText = modeList[2].modeName,
+ bottomText = modeList[2].modeDesc,
+ topColor = if (isEnable) if (isClicked) "#00BC71" else "#000000" else "#B4B4B4",
+ bottomColor = if (isEnable) "#8B8B8B" else "#B4B4B4"
+ )
+ }
+
+ private fun loadSamplingSpan(isClicked: Boolean = false, isEnable: Boolean = true) {
+ binding.rbModeSampling.text =
+ getModeTextSpan(
+ topText = modeList[1].modeName,
+ bottomText = modeList[1].modeDesc,
+ topColor = if (isEnable) if (isClicked) "#00BC71" else "#000000" else "#B4B4B4",
+ bottomColor = if (isEnable) "#8B8B8B" else "#B4B4B4"
+ )
+ }
+
+ private fun loadCookSpan(isClicked: Boolean = false, isEnable: Boolean = true) {
+ binding.rbModeCook.text =
+ getModeTextSpan(
+ topText = modeList[0].modeName,
+ bottomText = modeList[0].modeDesc,
+ topColor = if (isEnable) if (isClicked) "#00BC71" else "#000000" else "#B4B4B4",
+ bottomColor = if (isEnable) "#8B8B8B" else "#B4B4B4"
+ )
+ }
+
+ private fun getModeTextSpan(
+ topText: String,
+ topColor: String,
+ bottomText: String,
+ bottomColor: String
+ ): SpannableStringBuilder {
+
+
+ return buildSpannableString {
+ appendText(
+ topText,
+ ForegroundColorSpan(topColor.toColorInt()),
+ StyleSpan(Typeface.BOLD),
+ AbsoluteSizeSpan(36, true),
+ LineHeightSpan { text, start, end, spanstartv, v, fm ->
+ fm.descent += 10.dp // 增加行间距
+ }
+ )
+ append("\n")
+ appendText(
+ bottomText,
+ ForegroundColorSpan(bottomColor.toColorInt()),
+ AbsoluteSizeSpan(26, true)
+ )
+ }
+ }
+
+ fun saveSeasoning(entity: SeasoningEntity) {
+ appViewModel.saveSeasoning(entity){
+ toast("保存成功")
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/DishSamplingActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/DishSamplingActivity.kt
new file mode 100644
index 0000000..ba1612f
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/DishSamplingActivity.kt
@@ -0,0 +1,131 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.databinding.ActivitySamplingBinding
+import com.shuwei.dish.match.databinding.LayoutFoodRemindBinding
+import com.shuwei.dish.match.db.AppRepository
+import com.shuwei.dish.match.dialog.CommonDialog
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.ui.fragment.DishSamplingFragment
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.visible
+import com.shuwei.dish.match.viewmodel.AppViewModel
+import com.shuwei.dish.match.viewmodel.factory.AppFactory
+
+class DishSamplingActivity : BaseActivity() {
+
+ private lateinit var binding: ActivitySamplingBinding
+
+ var foodName: String? = null
+
+ companion object {
+ public const val FOOD_NAME = "foodName"
+ public const val PAGE_FROM = "pageFrom"
+ public const val HOME = "home"
+ }
+
+ private var pageFrom: String? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivitySamplingBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ pageFrom = intent.getStringExtra(PAGE_FROM)
+ setTitleBar()
+ setHeaderBackground()
+ initViewModel()
+ loadDishSamplingPage()
+ foodName = intent.getStringExtra(FOOD_NAME)
+ }
+
+ private fun setTitleBar() {
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "菜品采集"
+ }, rightIconActon = {
+ it.gone()
+ it.setImageResource(R.drawable.ic_setting)
+ it.setOnClickListener {
+ //startActivity()
+ }
+ }, backAction = {
+ it.visible()
+ it.setOnClickListener {
+ onBackPressed()
+ }
+ })
+ }
+
+ private var dishSamplingFragment: DishSamplingFragment? = null
+
+ private fun loadDishSamplingPage() {
+ if (dishSamplingFragment == null) {
+ dishSamplingFragment = DishSamplingFragment()
+ }
+ dishSamplingFragment?.let {
+ loadFragment(it)
+ }
+ }
+
+ private fun loadFragment(fragment: Fragment) {
+ supportFragmentManager.beginTransaction().apply {
+ replace(R.id.flContainer, fragment)
+ commit()
+ }
+ }
+
+ private lateinit var appViewModel: AppViewModel
+
+ private fun initViewModel() {
+ val db = BaseApp.instance!!.database
+ val factory =
+ AppFactory(AppRepository(db.appDao()))
+ appViewModel =
+ ViewModelProvider(this, factory)[AppViewModel::class.java]
+ }
+
+ fun getCookFoodList(action: (MutableList?) -> Unit) {
+ appViewModel.getCookFoodList(cookMode = 1) { action(it) }
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("GestureBackNavigation")
+ @Deprecated("Deprecated in Java")
+ override fun onBackPressed() {
+ val list = dishSamplingFragment?.list
+ if (list.isNullOrEmpty().not()) {
+ //说明有新增的食材
+ saveDataRemindDialog()
+ return
+ }
+ if (pageFrom == HOME) {
+ startActivity()
+ }
+ super.onBackPressed()
+ }
+
+ private fun saveDataRemindDialog() {
+ val remindBinding = LayoutFoodRemindBinding.inflate(layoutInflater)
+ remindBinding.tvDialogTitle.text = "温馨提示"
+ remindBinding.tvDialogContent.text = "您好,当前页面存在未保存的数据,确认返回吗?"
+ CommonDialog(this).apply {
+ messageView = remindBinding.root
+ leftText = "取消"
+ rightText = "确认"
+ onLeftClick = { dismiss() }
+ onRightClick = {
+ dismiss()
+ finish()
+ }
+ onDismiss = { hideStatusBar() }
+ }.show()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt
new file mode 100644
index 0000000..596f6e5
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt
@@ -0,0 +1,215 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.FoodRecordAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.databinding.ActivityFoodSearchBinding
+import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
+
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.entity.FoodRecordBean
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.utils.KeyboardUtil
+import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toObject
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+import java.io.Serializable
+
+class FoodSearchActivity : BaseActivity() {
+
+ companion object {
+ private const val TAG = "FoodSearchActivity"
+ const val PAGE_TYPE = "pageType"
+ const val FOOD_ID = "foodId"
+ const val FOOD_NAME = "foodName"
+ }
+
+ private lateinit var binding: ActivityFoodSearchBinding
+
+ private var list: MutableList = mutableListOf()
+ private var pageType = 0
+ private val recordAdapter by lazy {
+ FoodRecordAdapter(list).apply {
+ isStateViewEnable = true
+ setOnItemClickListener { adapter, view, position ->
+ if (pageType == 1) {
+ startActivity {
+ putExtra(PrepareCookActivity.FOOD_ITEM, list[position] as Serializable)
+ }
+ return@setOnItemClickListener
+ }
+ setResult(RESULT_OK, Intent().apply {
+ putExtra(FOOD_ID, list[position].foodId)
+ putExtra(FOOD_NAME, list[position].foodName)
+ })
+ finish()
+ }
+ }
+ }
+
+ private var foodName: String? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityFoodSearchBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ pageType = intent.getIntExtra(PAGE_TYPE, 0)
+ setHeaderBackground()
+ foodName = intent.getStringExtra(FOOD_NAME)
+ binding.etInputDish.setText(foodName)
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "菜品搜索"
+ }, rightIconActon = {
+ it.gone()
+ it.setImageResource(R.drawable.ic_setting)
+ it.setOnClickListener {
+ //startActivity()
+ }
+ })
+ binding.rvDishSearchList.run {
+ layoutManager =
+ LinearLayoutManager(this@FoodSearchActivity, LinearLayoutManager.VERTICAL, false)
+ adapter = recordAdapter
+ }
+ addViewListener()
+ }
+
+ private fun addViewListener() {
+ binding.ivDishSearch.setOnClickListener { v ->
+ pageNo = 1
+ getInputAndSearch()
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+ binding.refreshLayout.setEnableRefresh(true)
+ binding.refreshLayout.setEnableLoadMore(false)
+ binding.refreshLayout.setOnRefreshListener {
+ pageNo = 1
+ getInputAndSearch()
+ }
+
+ binding.refreshLayout.setOnLoadMoreListener {
+ getInputAndSearch()
+ }
+ if (foodName.isNullOrBlank().not()) {
+ pageNo = 1
+ queryListInfo(foodName!!)
+ }
+ binding.root.setOnClickListener { v ->
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+ binding.etInputDish.let { v ->
+ v.addOnActionSearchListener {
+ pageNo = 1
+ getInputAndSearch()
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+ }
+ }
+
+ private fun getInputAndSearch() {
+ val input = binding.etInputDish.text.toString().trim()
+ if (input.isBlank()) {
+ toast("请输入菜品名称")
+ binding.refreshLayout.finishRefresh()
+ return
+ }
+ queryListInfo(input)
+ }
+
+ private var pageNo = 1
+ private var pageSize = 100
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun queryListInfo(input: String) {
+ showLoading()
+ val map = mapOf(
+ "foodName" to input.trim(),
+ "pageNo" to "$pageNo",
+ "pageSize" to "$pageSize",
+ "canteenId" to "0"
+ )
+ val sb = StringBuilder(UrlConfig.QUERY_FOOD_LIST).apply {
+ append("?")
+ map.forEach { (key, value) -> append("$key=$value&") }
+ }
+ sb.deleteCharAt(sb.length - 1)
+ HttpUtil.get(
+ url = sb.toString(),
+ doSuccess = {
+ delayDismissLoading()
+ finishRefresh()
+ binding.refreshLayout.run {
+ setEnableRefresh(true)
+ }
+ val json = it.toJsonString()
+ val recordBean: FoodRecordBean? = json.toObject()
+ if (recordBean == null || recordBean.records.isNullOrEmpty()) {
+// toast("暂未搜索到相关菜品信息")
+ if (pageNo == 1) {
+ loadEmptyView()
+ }
+ return@get
+ }
+ val records = recordBean.records
+ if (pageNo == 1) {
+ list.clear()
+ }
+ list.addAll(records!!)
+ recordAdapter.notifyDataSetChanged()
+ val isLoadMoreEnable = records.size >= pageSize
+ binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
+ if (isLoadMoreEnable) {
+ pageNo++
+ }
+ },
+ doFailure = { code, msg ->
+ binding.refreshLayout.run {
+ setEnableRefresh(true)
+ }
+ toast(msg)
+ delayDismissLoading()
+ finishRefresh()
+ if (pageNo == 1) {
+ loadEmptyView()
+ }
+ }
+ )
+ }
+ private fun finishRefresh() {
+ if (pageNo == 1) {
+ binding.refreshLayout.finishRefresh(1200)
+ } else {
+ binding.refreshLayout.finishLoadMore(1200)
+ }
+ }
+
+ private var emptyViewBinding: LayoutEmptyViewBinding? = null
+ @SuppressLint("NotifyDataSetChanged")
+ private fun loadEmptyView() {
+ list.clear()
+ recordAdapter.notifyDataSetChanged()
+ if (emptyViewBinding == null) {
+ emptyViewBinding = LayoutEmptyViewBinding.inflate(LayoutInflater.from(this), binding.rvDishSearchList, false)
+ }
+ emptyViewBinding!!.tvContent.text = "暂无数据"
+ emptyViewBinding!!.tvSubContent.text = "可以尝试换个名称重新搜索"
+ recordAdapter.stateView = emptyViewBinding!!.root
+
+ binding.refreshLayout.run {
+ setEnableRefresh(false)
+ setEnableLoadMore(false)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/HomeActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/HomeActivity.kt
new file mode 100644
index 0000000..2a46941
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/HomeActivity.kt
@@ -0,0 +1,156 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.provider.Settings
+import android.util.Log
+import androidx.lifecycle.ViewModelProvider
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.aithings.Weigher
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.HomeModeAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.databinding.ActivityHomeBinding
+import com.shuwei.dish.match.db.AppRepository
+import com.shuwei.dish.match.entity.HomeModeBean
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.utils.WeightUtil
+import com.shuwei.dish.match.utils.ext.put
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.viewmodel.AppViewModel
+import com.shuwei.dish.match.viewmodel.factory.AppFactory
+
+class HomeActivity : BaseActivity() {
+
+ companion object {
+ const val TAG = "HomeActivity"
+ }
+
+ private lateinit var binding: ActivityHomeBinding
+
+ private var connect: Boolean = false
+
+ @SuppressLint("HardwareIds")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ statusBarDarkFont(enable = true)
+ initViewModel()
+ // 获取 ANDROID_ID
+ BaseApp.instance?.androidId =
+ Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
+
+ binding = ActivityHomeBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setHeaderBackground(isHomePage = true)
+
+ initRecyclerView()
+ getAppToken()
+ WeightUtil.connect { connect ->
+ this.connect = connect
+ }
+ Weigher.init()
+ Weigher.getWeight()
+ Weigher.startContinuousRead()
+// binding.tvTopText.setOnClickListener {
+// startActivity()
+// }
+
+// appViewModel.deleteEmptySeasoning()
+// appViewModel.deleteCookFoodAndGoods(0,"") {}
+// appViewModel.getCookFoodGoodsList("") {goodsList->
+// goodsList.forEach {
+// it.foodId = "1594990392084779010"
+// appViewModel.updateGoods(it)
+// }
+// }
+// appViewModel.deleteAll()
+
+ }
+
+ private fun initRecyclerView() {
+ initModeList()
+ binding.rvModeList.run {
+ layoutManager =
+ LinearLayoutManager(this@HomeActivity, LinearLayoutManager.VERTICAL, false)
+ adapter = modeAdapter
+ }
+ }
+
+ private val modeList = mutableListOf()
+ private val modeAdapter by lazy {
+ HomeModeAdapter(modeList).apply {
+ addOnItemChildClickListener(R.id.layoutCard) { adapter, view, position ->
+ modeList[position].onClick?.invoke()
+ }
+ }
+ }
+
+ private fun initModeList() {
+ modeList.add(
+ HomeModeBean(
+ modeName = "制作模式",
+ modeDesc = "菜品快速制作,记录熟重",
+ modeIconId = R.drawable.ic_mode_cook,
+ onClick = {
+ startActivity()
+ finish()
+ })
+ )
+ modeList.add(
+ HomeModeBean(
+ modeName = "采样模式",
+ modeDesc = "菜品快速制作,记录熟重",
+ modeIconId = R.drawable.ic_mode_sampling,
+ onClick = {
+ goSampling()
+ })
+ )
+ modeList.add(
+ HomeModeBean(
+ modeName = "品控模式",
+ modeDesc = "菜品快速制作,记录熟重",
+ modeIconId = R.drawable.ic_mode_quality,
+ isLocked = true,
+ onClick = {
+ toast("即将解锁")
+ })
+ )
+ }
+
+ private lateinit var appViewModel: AppViewModel
+
+ private fun initViewModel() {
+ val db = BaseApp.instance!!.database
+ val factory = AppFactory(AppRepository(db.appDao()))
+ appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
+ }
+
+ private fun goSampling() {
+ appViewModel.countCookFood(cookMode = 1) {
+ if (it > 0) {
+ startActivity()
+ finish()
+ return@countCookFood
+ }
+ startActivity {
+ putExtra(DishSamplingActivity.PAGE_FROM, DishSamplingActivity.HOME)
+ }
+ finish()
+ }
+ }
+
+ private fun getAppToken() {
+ val url = "${UrlConfig.GET_TOKEN}?qrcodeId=${BaseApp.instance?.androidId}"
+// Log.d(TAG, "getToken: url = $url")
+ HttpUtil.get(url = url, doSuccess = {
+ BaseApp.getSharedPref()?.put("token" to it)
+ BaseApp.instance?.token = it.toString()
+ }) { code, msg ->
+ toast(msg)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/PrepareCookActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/PrepareCookActivity.kt
new file mode 100644
index 0000000..54aeedd
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/PrepareCookActivity.kt
@@ -0,0 +1,316 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.graphics.Typeface
+import android.os.Bundle
+import android.util.Log
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.aithings.Weigher
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.DishPartAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.databinding.ActivityPrepareCookBinding
+import com.shuwei.dish.match.databinding.LayoutFoodRemindBinding
+import com.shuwei.dish.match.dialog.BottomDialog
+import com.shuwei.dish.match.dialog.CommonDialog
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.utils.SwipeCallback
+import com.shuwei.dish.match.utils.WeightUtil
+import com.shuwei.dish.match.utils.ext.clickWithDebounce
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toObject
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+import java.io.Serializable
+
+@SuppressLint("NotifyDataSetChanged")
+class PrepareCookActivity : BaseActivity() {
+
+ companion object {
+ const val TAG = "CookActivity"
+ const val FOOD_ITEM = "foodItem"
+ }
+
+ private lateinit var binding: ActivityPrepareCookBinding
+
+ private var food: FoodRecord? = null
+
+ private var goodsList: MutableList? = null
+
+ @Suppress("DEPRECATION")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityPrepareCookBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setHeaderBackground()
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "菜品制作"
+ }, rightIconActon = {
+ it.gone()
+ it.setImageResource(R.drawable.ic_setting)
+ it.setOnClickListener {
+ //startActivity()
+ }
+ }, backAction = {
+ it.setOnClickListener {
+ onBackPressed()
+ }
+ })
+ food = intent.extras?.getSerializable(FOOD_ITEM) as FoodRecord?
+ binding.tvDishName.text = food?.foodName ?: ""
+ addViewClickListener()
+ getDishDetail()
+ }
+
+ private fun addViewClickListener() {
+ binding.ivWeightClear.setOnClickListener {
+ Weigher.tareTwo(2)
+ }
+ WeightUtil.addWeightListener(getWeight = { address, state, weight ->
+ Log.d(TAG, "addViewClickListener: address=$address,state=$state,weight=$weight")
+ if (address == 2) {
+ binding.tvDishPartWeight.text = "${weight}"
+ }
+ })
+ binding.ivWeightAdd.setOnClickListener {
+ if (clickIndex == -1) {
+ toast("请选择菜品构成")
+ return@setOnClickListener
+ }
+ val clickItem = list[clickIndex]
+ clickItem.run {
+ if (isNewDishType && materialType != 1 && materialType != 2) {
+ toast("请选择主辅材类型")
+ return@setOnClickListener
+ }
+ }
+ val weight = binding.tvDishPartWeight.text.toString().toInt()
+ if (weight <= 0) {
+ toast("食材用量需要大于0")
+ return@setOnClickListener
+ }
+ Log.d(TAG, "addViewClickListener->useRealWeight=$weight")
+ clickItem.run {
+ useWeight = weight
+ isSetFinished = true
+ dishPartAdapter.notifyItemChanged(clickIndex)
+ }
+ }
+ binding.tvAddFood.clickWithDebounce {
+ BottomDialog(goodsType = 0).show(this) { item ->
+ val filterResult = list.firstOrNull { it.goodsId == item.goodsId }
+ if (filterResult != null) {
+ toast("不允许重复添加同一食材")
+ return@show
+ }
+ list.add(CookFoodGoodsEntity().apply {
+ goodsId = item.goodsId
+ goodsName = item.goodsName
+// materialType =
+ isNewDishType = true
+ })
+ onItemClick(list.size - 1)
+ }
+ }
+ binding.btnCook.clickWithDebounce {
+ val count = list.count { it.isSetFinished.not() }
+ if (count > 0) {
+ showRemindDialog()
+ return@clickWithDebounce
+ }
+ goToSubmit()
+ }
+ binding.rgCook.setOnCheckedChangeListener { group, checkedId ->
+ val tempType =
+ if (checkedId == R.id.rbDishTypeFirst) 1 else if (checkedId == R.id.rbDishTypeSecond) 2 else -1
+ list[clickIndex].materialType = tempType
+ dishPartAdapter.notifyItemChanged(clickIndex)
+
+ binding.tvDishType.text =
+ if (tempType == 1) "主材" else if (tempType == 2) "辅材" else ""
+ }
+ }
+
+ private fun goToSubmit() {
+ getGoodsList()
+ if (goodsList.isNullOrEmpty()) {
+ toast("菜品构成信息未设置")
+ return
+ }
+ Log.d(TAG, "goToSubmit: goodsList:${goodsList?.toJsonString()}")
+ startActivity(
+ Intent(this, SubmitDishActivity::class.java)
+ .putExtra(SubmitDishActivity.GOODS_LIST, goodsList as Serializable)
+ .putExtra(SubmitDishActivity.FOOD_ITEM, food as Serializable)
+ )
+ }
+
+ private fun getGoodsList() {
+ if (goodsList == null) {
+ goodsList = mutableListOf()
+ }
+ list.forEach {
+ if (it.isSetFinished) {
+ goodsList?.add(CookFoodGoodsEntity().apply {
+ foodId = food!!.foodId
+ goodsId = it.goodsId
+ relateionType = it.relateionType
+ allEdible = it.allEdible
+ goodsName = it.goodsName
+ materialType = it.materialType
+ useWeight = it.useWeight ?: 0
+ goodsOrRelationCode = it.goodsOrRelationCode
+ })
+ }
+ }
+ }
+
+ private fun showRemindDialog() {
+ val remindBinding = LayoutFoodRemindBinding.inflate(layoutInflater)
+ CommonDialog(this).apply {
+ messageView = remindBinding.root
+ leftText = "返回调整"
+ rightText = "确认无误"
+ onLeftClick = { dismiss() }
+ onRightClick = {
+ goToSubmit()
+ dismiss()
+ }
+ onDismiss = { hideStatusBar() }
+ }.show()
+ }
+
+
+ private fun getDishDetail() {
+ //649
+ val url = "${UrlConfig.DISH_DETAIL}?foodId=${food?.foodId}"
+ HttpUtil.get(
+ url = url,
+ doSuccess = {
+ val json = it.toJsonString()
+ Log.d(TAG, "getDishDetail: json:$json")
+ val detail: CookFoodEntity? = json.toObject()
+ if (detail == null) {
+ toast("查询菜品信息为空")
+ return@get
+ }
+ loadDishDetail(detail)
+ }) { code, msg ->
+ toast(msg)
+ }
+ }
+
+ private fun loadDishDetail(detail: CookFoodEntity) {
+ val voList = detail.stFoodInfoConstituteList
+ if (voList.isNullOrEmpty()) {
+ return
+ }
+ //筛选出主材和辅材
+ val tempDate = voList.filter { it.materialType == 1 || it.materialType == 2 }
+ .apply {
+ forEach { it.useWeight = 0 }
+ }
+ list.clear()
+ list.addAll(tempDate)
+ firstReqSize = list.size
+ initRecyclerView()
+ }
+
+ private var firstReqSize = 0
+ private val list = mutableListOf()
+ private val dishPartAdapter by lazy {
+ DishPartAdapter(list).apply {
+ setOnItemClickListener { _, _, positon ->
+ onItemClick(positon)
+ }
+ }
+ }
+
+ private fun onItemClick(positon: Int) {
+ this@PrepareCookActivity.clickIndex = positon
+ list[clickIndex].let { it ->
+ binding.tvDishShowName.run {
+ text = it.goodsName
+ setTypeface(typeface, Typeface.BOLD)
+ }
+ binding.tvDishType.text =
+ if (it.materialType == 1) "主材" else if (it.materialType == 2) "辅材" else ""
+ list.forEach { bean -> bean.isItemClicked = false }
+ it.isItemClicked = true
+ dishPartAdapter.notifyDataSetChanged()
+
+ if (it.isNewDishType) {
+ binding.dividerDishType.visible()
+ binding.llDishType.visible()
+ } else {
+ binding.dividerDishType.gone()
+ binding.llDishType.gone()
+ }
+ }
+ }
+
+ private var clickIndex = -1
+
+ private fun initRecyclerView() {
+ binding.rvDishPartList.run {
+ layoutManager =
+ LinearLayoutManager(this@PrepareCookActivity, LinearLayoutManager.VERTICAL, false)
+ adapter = dishPartAdapter
+ val itemTouchHelper = ItemTouchHelper(SwipeCallback(dishPartAdapter) { position ->
+ if (list[position].isNewDishType.not()) {
+ toast("只能删除刚添加的食材")
+ dishPartAdapter.notifyItemChanged(position)
+ return@SwipeCallback
+ }
+ dishPartAdapter.removeAt(position)
+ toast("已删除")
+ })
+ itemTouchHelper.attachToRecyclerView(this)
+ }
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("GestureBackNavigation")
+ @Deprecated("Deprecated in Java")
+ override fun onBackPressed() {
+ if (list.size > firstReqSize) {
+ //说明有新增的食材
+ saveDataRemindDialog()
+ return
+ }
+ val filterResult = list.firstOrNull { (it.useWeight ?: 0) > 0 }
+ if (filterResult != null) {
+ //说明有称重的数据
+ saveDataRemindDialog()
+ return
+ }
+ super.onBackPressed()
+ }
+
+ private fun saveDataRemindDialog() {
+ val remindBinding = LayoutFoodRemindBinding.inflate(layoutInflater)
+ remindBinding.tvDialogTitle.text = "温馨提示"
+ remindBinding.tvDialogContent.text = "您好,当前页面存在尚未保存的数据,确认返回上页吗?"
+ CommonDialog(this).apply {
+ messageView = remindBinding.root
+ leftText = "取消"
+ rightText = "确认"
+ onLeftClick = { dismiss() }
+ onRightClick = {
+ dismiss()
+ finish()
+ }
+ onDismiss = { hideStatusBar() }
+ }.show()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SamplingListActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SamplingListActivity.kt
new file mode 100644
index 0000000..69cde07
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/SamplingListActivity.kt
@@ -0,0 +1,111 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.Intent
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.databinding.ActivitySamplingBinding
+import com.shuwei.dish.match.db.AppRepository
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.ui.fragment.SamplingListFragment
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+import com.shuwei.dish.match.viewmodel.AppViewModel
+import com.shuwei.dish.match.viewmodel.factory.AppFactory
+
+class SamplingListActivity : BaseActivity() {
+
+ private lateinit var binding: ActivitySamplingBinding
+
+ companion object {
+ const val IS_COOKING = "isCooking"
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivitySamplingBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setTitleBar()
+ setHeaderBackground()
+ initViewModel()
+ loadSamplingListPage()
+ }
+
+ private fun setTitleBar() {
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "采样历史"
+ }, rightIconActon = {
+ it.visible()
+ it.setImageResource(R.drawable.ic_setting)
+ it.setOnClickListener {
+ startActivity {
+ putExtra(DeviceSettingActivity.COOK_MODE, 2)
+ }
+ }
+ }, backAction = {
+ it.gone()
+ })
+
+
+ }
+
+ private var samplingListFragment: SamplingListFragment? = null
+
+ private fun loadSamplingListPage() {
+ if (samplingListFragment == null) {
+ samplingListFragment = SamplingListFragment()
+ }
+ samplingListFragment?.let {
+ loadFragment(it)
+ }
+ }
+
+ private fun loadFragment(fragment: Fragment) {
+ supportFragmentManager.beginTransaction().apply {
+ replace(R.id.flContainer, fragment)
+ commit()
+ }
+ }
+
+ private lateinit var appViewModel: AppViewModel
+
+ private fun initViewModel() {
+ val db = BaseApp.instance!!.database
+ val factory =
+ AppFactory(AppRepository(db.appDao()))
+ appViewModel =
+ ViewModelProvider(this, factory)[AppViewModel::class.java]
+ }
+
+ fun getCookFoodList(action: (MutableList?) -> Unit) {
+ appViewModel.getCookFoodList(cookMode = 1) { action(it) }
+ }
+
+ fun deleteCookFoodAndGoods(foodId: String, action: () -> Unit) {
+ appViewModel.deleteCookFoodAndGoods(cookMode = 1, foodId = foodId, onFinish = action)
+ }
+
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ val isCooking = intent?.getBooleanExtra(IS_COOKING, false) ?: false
+ samplingListFragment?.refreshPage(isCooking)
+ }
+
+ @Deprecated("Deprecated in Java")
+ @SuppressLint("GestureBackNavigation", "MissingSuperCall")
+ override fun onBackPressed() {
+ //super.onBackPressed()
+ //当前页面不允许返回
+ //dialog = toast("不允许返回操作")
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SelectDishActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SelectDishActivity.kt
new file mode 100644
index 0000000..f5f00b3
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/SelectDishActivity.kt
@@ -0,0 +1,138 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.Intent
+import android.os.Bundle
+import androidx.lifecycle.ViewModelProvider
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.databinding.ActivitySelectDishBinding
+import com.shuwei.dish.match.db.AppRepository
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.ui.fragment.DishListFragment
+import com.shuwei.dish.match.utils.KeyboardUtil
+import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+import com.shuwei.dish.match.viewmodel.AppViewModel
+import com.shuwei.dish.match.viewmodel.factory.AppFactory
+
+class SelectDishActivity : BaseActivity() {
+
+ companion object {
+ const val IS_COOKING = "isCooking"
+ }
+
+ private lateinit var binding: ActivitySelectDishBinding
+ private var dishListFragment: DishListFragment? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivitySelectDishBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setHeaderBackground()
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "选择菜品"
+ }, rightIconActon = {
+ it.visible()
+ it.setImageResource(R.drawable.ic_setting)
+ it.setOnClickListener {
+ startActivity {
+ putExtra(DeviceSettingActivity.COOK_MODE, 1)
+ }
+ }
+ }, backAction = {
+ it.gone()
+ })
+ initViewModel()
+ addViewListener()
+ loadFragment()
+ }
+
+ private lateinit var appViewModel: AppViewModel
+
+ var dinnerType: String = "早餐"
+
+ private fun initViewModel() {
+ val db = BaseApp.instance!!.database
+ val factory =
+ AppFactory(AppRepository(db.appDao()))
+ appViewModel =
+ ViewModelProvider(this, factory)[AppViewModel::class.java]
+ }
+
+ fun getCookFoodList(action: (MutableList?) -> Unit) {
+ appViewModel.getCookFoodList(cookMode = 0) { action(it) }
+ }
+
+ fun addViewListener() {
+ binding.dishRadioGroup.setOnCheckedChangeListener { _, checkedId ->
+ dinnerType = when (checkedId) {
+ R.id.rbBreakfast -> "早餐"
+ R.id.rbLunch -> "午餐"
+ R.id.rbDinner -> "晚餐"
+ else -> ""
+ }
+ dishListFragment?.getDishList(1, false)
+ }
+// binding.llSearchBar.setOnClickListener {
+// startActivity {
+// putExtra(FoodSearchActivity.PAGE_TYPE, 1)
+// }
+// }
+ binding.etInputDish.addOnActionSearchListener {
+ jumpSearch()
+ }
+ binding.ivDishSearch.setOnClickListener {
+ jumpSearch()
+ }
+ }
+
+ private fun jumpSearch() {
+ val searchText = binding.etInputDish.text.toString().trim()
+ if (searchText.isBlank()) {
+ toast(binding.etInputDish.hint.toString())
+ return
+ }
+ startActivity {
+ putExtra(FoodSearchActivity.PAGE_TYPE, 1)
+ putExtra(FoodSearchActivity.FOOD_NAME, searchText)
+ }
+ KeyboardUtil.hideKeyboard(this, binding.etInputDish)
+ }
+
+ private fun loadFragment() {
+ DishListFragment.instance().let {
+ dishListFragment = it
+ supportFragmentManager.beginTransaction().apply {
+ replace(R.id.flSubPage, it)
+ commit()
+ }
+ }
+ }
+
+ fun deleteCookFoodAndGoods(foodId: String, action: () -> Unit) {
+ appViewModel.deleteCookFoodAndGoods(cookMode = 0, foodId = foodId, onFinish = action)
+ }
+
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ val isCooking = intent?.getBooleanExtra(IS_COOKING, false) ?: false
+ dishListFragment?.getDishList(1, isCooking)
+ }
+
+ @Deprecated("Deprecated in Java")
+ @SuppressLint("GestureBackNavigation", "MissingSuperCall")
+ override fun onBackPressed() {
+ //super.onBackPressed()
+ //当前页面不允许返回
+// dialog = toast("不允许返回操作")
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SubmitDishActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SubmitDishActivity.kt
new file mode 100644
index 0000000..5834d4a
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/SubmitDishActivity.kt
@@ -0,0 +1,393 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.util.Log
+import android.util.SparseArray
+import android.util.SparseIntArray
+import androidx.core.util.forEach
+import androidx.lifecycle.ViewModelProvider
+import com.aithings.Weigher
+import com.google.gson.reflect.TypeToken
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.SeasoningCellTool
+import com.shuwei.dish.match.adapter.TextCellAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.databinding.ActivitySubmitDishBinding
+import com.shuwei.dish.match.db.AppRepository
+
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.entity.SeasoningEntity
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.utils.DataUtil
+import com.shuwei.dish.match.utils.WeightUtil
+import com.shuwei.dish.match.utils.ext.clickWithDebounce
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toType
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+import com.shuwei.dish.match.viewmodel.AppViewModel
+import com.shuwei.dish.match.viewmodel.factory.AppFactory
+
+@SuppressLint("UseSparseArrays")
+class SubmitDishActivity : BaseActivity() {
+
+ companion object {
+ const val TAG = "SubmitDishActivity"
+ const val FOOD_ITEM = "foodItem"
+ const val GOODS_LIST = "goodsList"
+ }
+
+ private lateinit var binding: ActivitySubmitDishBinding
+
+ private var food: FoodRecord? = null
+ private var goodsList: MutableList? = null
+
+ private var isCooking = false
+
+ private val cookFoodEntity by lazy {
+ CookFoodEntity().apply {
+ food?.let {
+ foodId = it.foodId ?: ""
+ foodName = it.foodName
+ cookMode = it.cookMode
+ }
+ canteenId = 0
+ }
+ }
+
+ @Suppress("unchecked_cast", "DEPRECATION")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivitySubmitDishBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ initViewModel()
+ setHeaderBackground()
+ intent.extras?.apply {
+ food = getSerializable(FOOD_ITEM) as FoodRecord?
+ Log.d(TAG, "onCreate: cookMode=${food?.cookMode}")
+ isCooking = food?.isCooking ?: false
+ if (isCooking) {
+ //烹饪中,从本地查询数据
+ loadSeasoningFromLocal()
+ } else {
+ //非烹饪中,从菜品主辅材配置页面带入数据
+ goodsList = getSerializable(GOODS_LIST) as MutableList?
+ }
+ }
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = food?.foodName
+ }, rightIconActon = {
+ it.gone()
+ it.setImageResource(R.drawable.ic_setting)
+ it.setOnClickListener {
+ //startActivity()
+ }
+ })
+ addViewListener()
+ }
+
+ private fun loadSeasoningFromLocal() {
+ appViewModel.getCookFoodGoodsList(food?.foodId!!) { it ->
+ goodsList = mutableListOf()
+ //设置主辅材数据
+ goodsList?.addAll(it.filter { goods -> goods.materialType != 3 })
+
+ //获取调料数据并展示
+ val filterList: List? = it.filter { goods -> goods.materialType == 3 }
+ .map { entity ->
+ SeasoningEntity().also { se ->
+ se.goodsId = entity.goodsId
+ se.goodsName = entity.goodsName
+ se.goodsOrRelationCode = entity.goodsOrRelationCode
+ se.relateionType = entity.relateionType
+ se.materialType = entity.materialType
+ se.allEdible = entity.allEdible
+ se.useWeight = entity.useWeight
+ se.popularName = entity.popularName
+ se.canteenId = entity.canteenId
+ se.relateionType_dictText = entity.relateionType_dictText
+ se.foodId = entity.foodId
+ se.sort = entity.sort
+ se.pageType = 0
+ }
+ }
+ filterList?.toMutableList()?.let { cellData ->
+ loadTextCell(cellData)
+ }
+ }
+ }
+
+
+ private lateinit var seasoningList: List
+ private var isFirstSave = true
+ fun updateSeasoningList(list: MutableList) {
+ if (isFirstSave) {
+ val json = list.toJsonString()
+ val typeToken = object : TypeToken>() {}
+ seasoningList = json.toType(typeToken = typeToken)
+ isFirstSave = false
+ }
+ }
+
+ private val seasoningArray by lazy {
+ SparseArray()
+ }
+
+
+ private val firstGoodsArray by lazy {
+ SparseArray()
+ }
+
+ private fun addViewListener() {
+ addWeightListener()
+ binding.btnWeightClear.setOnClickListener { Weigher.tareTwo(1) }
+
+ binding.btnCook.clickWithDebounce {
+ cook()
+ }
+
+ binding.btnSubmit.clickWithDebounce {
+ if (cookFoodEntity.foodWeight <= 0) {
+ toast("未识别到菜品熟重")
+ return@clickWithDebounce
+ }
+ submit()
+ }
+ }
+
+ private fun addWeightListener() {
+ WeightUtil.addWeightListener(getWeight = { address, state, weight ->
+ if (address == 1) {
+ cookFoodEntity.foodWeight = weight
+ binding.tvTotalWeight.text = "${weight / 1000f}"
+ }
+// if (state != SensorScale.STATE_STABLE) {
+// return@addWeightListener
+// }
+ val firstWeight = firstGoodsArray.get(address, null)
+ if (firstWeight != weight) {
+ Log.d(
+ TAG,
+ "addViewListener: state=$state,address=$address,weight=$weight,firstWeight=$firstWeight"
+ )
+ }
+ if (firstWeight == null) {
+ //未设置数据
+ firstGoodsArray.put(address, weight)
+ return@addWeightListener
+ }
+// val cookingWeight =
+// if (isCooking && seasoningList.isNullOrEmpty().not())
+// seasoningList?.get(weightRelateArray2.get(address))?.weight ?: 0
+// else 0
+// var realUseWeight = firstWeight - weight + cookingWeight
+ var realUseWeight = firstWeight - weight
+ realUseWeight = if (realUseWeight > 0) realUseWeight else 0
+// Log.d(
+// TAG,
+// "addViewListener: state=$state,address=$address,总共使用重量:$realUseWeight"
+// )
+ seasoningArray.put(address, realUseWeight)
+
+ refreshSeasoningWeight()
+ })
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun refreshSeasoningWeight() {
+ binding.rvSeasoning.adapter?.let { adapter ->
+ if (adapter is TextCellAdapter) {
+ adapter.list.let { items ->
+ weightRelateArray.forEach { key, value ->
+ items[key].useWeight =
+ (seasoningArray.get(value) ?: 0) + getCookingSeasoning(value)
+ }
+ }
+ adapter.notifyDataSetChanged()
+ TextCellAdapter.loadCell(binding.tvRightBottomCell, adapter.list[14])
+ }
+ }
+ }
+
+ private fun getCookingSeasoning(address: Int): Int {
+ if (isCooking.not()) return 0
+ if (seasoningList.isEmpty()) return 0
+ val weight = seasoningList[weightRelateArray2.get(address)].useWeight ?: 0
+ //Log.i(TAG, "getCookingSeasoning: weight[${address}]=$weight,seasoningList=${seasoningList.toJsonString()}")
+ return weight
+ }
+
+ private val weightRelateArray2 by lazy {
+ SparseIntArray().apply {
+ weightRelateArray.forEach { key, value ->
+ if (value == 3) {
+ put(3, 14)
+ } else {
+ put(value, key)
+ }
+ }
+ }
+ }
+
+ private val weightRelateArray by lazy {
+ DataUtil.getWeighAddressArray()
+ }
+
+// private fun prepareData(acton: () -> Unit) {
+//
+// //只有制作和采样列表页面才能进入设置页面,提交页面无法进行设置,不存在调料数据被修改的问题
+// val seasoningJson = realSeasoningData.toJsonString()
+// val typeToken = object : TypeToken>() {}
+// val tempSeasoningList = seasoningJson.toType(typeToken = typeToken)
+// goodsList?.addAll(tempSeasoningList)
+// acton()
+//
+// }
+
+ private fun cook() {
+ if (food == null || goodsList.isNullOrEmpty()) {
+ toast("未获取到菜品或构成信息")
+ return
+ }
+ val realSeasoningData = (binding.rvSeasoning.adapter as TextCellAdapter).list
+ if (realSeasoningData.isEmpty() && !isCooking) {
+ toast("未获取到调料信息")
+ return
+ }
+ showLoading()
+ //只有制作和采样列表页面才能进入设置页面,提交页面无法进行设置,不存在调料数据被修改的问题
+ val seasoningJson = realSeasoningData.toJsonString()
+ val typeToken = object : TypeToken>() {}
+ val tempSeasoningList = seasoningJson.toType(typeToken = typeToken)
+ goodsList?.addAll(tempSeasoningList)
+
+ val isSamplingData = food!!.cookMode == 1
+ if (isSamplingData) {
+ //生成临时foodId,解决采样模式没有foodId,无法关联数据的问题
+ val tempFoodId = cookFoodEntity.foodId.ifBlank { "${System.currentTimeMillis()}" }
+ cookFoodEntity.foodId = tempFoodId
+ }
+ //全部设置同一foodId
+ goodsList?.forEach {
+ it.foodId = cookFoodEntity.foodId
+ }
+ //保存菜品-保存主辅料调料
+ appViewModel.saveCookFoodAndGoods(
+ cookMode = food!!.cookMode,
+ entity = cookFoodEntity,
+ list = goodsList,
+ onFinish = {
+ runOnUiThread {
+ dismissLoading()
+ jumpPage(isSamplingData, true)
+ }
+ })
+ }
+
+ private fun submit() {
+ if (food == null || goodsList.isNullOrEmpty()) {
+ toast("未获取到菜品或构成信息")
+ return
+ }
+ val realSeasoningData = (binding.rvSeasoning.adapter as TextCellAdapter).list
+ if (realSeasoningData.isEmpty() && !isCooking) {
+ toast("未获取到调料信息")
+ return
+ }
+ showLoading()
+ //只有制作和采样列表页面才能进入设置页面,提交页面无法进行设置,不存在调料数据被修改的问题
+ val seasoningJson = realSeasoningData.toJsonString()
+ val typeToken = object : TypeToken>() {}
+ val tempSeasoningList = seasoningJson.toType(typeToken = typeToken)
+ tempSeasoningList.forEach { entity ->
+ val realWeight = entity.useWeight ?: 0
+ val filterData = goodsList?.firstOrNull { it.goodsId == entity.goodsId }
+ //确保重量大于0,且无重复数据
+ if (realWeight > 0 && filterData == null) {
+ goodsList?.add(entity)
+ }
+ }
+
+ cookFoodEntity.stFoodInfoConstituteList = this@SubmitDishActivity.goodsList
+ val isSamplingData = food!!.cookMode == 1
+ if (isSamplingData) {
+ //采样模式没有foodId
+ cookFoodEntity.foodId = ""
+ goodsList?.forEach { it.foodId = "" }
+ }
+ val json = cookFoodEntity.toJsonString()
+ Log.d(TAG, "submit: json=$json")
+ HttpUtil.postJson(
+ url = UrlConfig.SUBMIT_DISH,
+ json = json,
+ doSuccess = {
+ Log.d(TAG, "submit: postJson=$it")
+ //删除本地数据
+ appViewModel.deleteCookFoodAndGoods(
+ cookMode = food!!.cookMode,
+ foodId = food!!.foodId!!
+ ) {
+ dismissLoading()
+ jumpPage(isSamplingData, false)
+ }
+ }, doFailure = { code, msg ->
+ Log.d(TAG, "submit: postJson:code=$code,msg=$msg")
+ toast(msg)
+ dismissLoading()
+ })
+ }
+
+ private fun jumpPage(isSampling: Boolean, isCooking: Boolean) {
+ if (isSampling) {
+ startActivity {
+ putExtra(SelectDishActivity.IS_COOKING, isCooking)
+ }
+ return
+ }
+ startActivity {
+ putExtra(SelectDishActivity.IS_COOKING, isCooking)
+ }
+ }
+
+ private lateinit var appViewModel: AppViewModel
+
+ private fun initViewModel() {
+ val db = BaseApp.instance!!.database
+ val factory =
+ AppFactory(AppRepository(db.appDao()))
+ appViewModel =
+ ViewModelProvider(this, factory)[AppViewModel::class.java]
+ }
+
+ override fun onResume() {
+ super.onResume()
+ binding.tvRightBottomCell.visible()
+ if (isCooking.not()) {
+ //烹饪中使用本地数据,未烹饪则使用默认的调料配置数据
+ appViewModel.loadSeasoning {
+ Log.d(TAG, "onResume: loadSeasoning:${it.toJsonString()}")
+ loadTextCell(it)
+ }
+ }
+ }
+
+ private fun loadTextCell(list: MutableList) {
+ SeasoningCellTool.loadData(
+ activity = this,
+ initList = list,
+ recyclerView = binding.rvSeasoning,
+ tvCell = binding.tvRightBottomCell
+ )
+ }
+}
+
+
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishListFragment.kt b/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishListFragment.kt
new file mode 100644
index 0000000..ee60de9
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishListFragment.kt
@@ -0,0 +1,243 @@
+package com.shuwei.dish.match.ui.fragment
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.shuwei.dish.match.adapter.DishShowAdapter
+import com.shuwei.dish.match.databinding.FragmentDishListBinding
+import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
+
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.entity.FoodRecordBean
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.ui.PrepareCookActivity
+import com.shuwei.dish.match.ui.SelectDishActivity
+import com.shuwei.dish.match.ui.SubmitDishActivity
+import com.shuwei.dish.match.utils.SwipeCallback
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toObject
+import com.shuwei.dish.match.utils.ext.toast
+import java.io.Serializable
+
+class DishListFragment : Fragment() {
+
+ companion object {
+ private const val TAG = "DishListFragment"
+
+ // const val DINNER_TYPE = "dinnerType"
+ public fun instance(): DishListFragment {
+ return DishListFragment().apply {
+// arguments = Bundle().apply {
+// putInt(DINNER_TYPE, type)
+// }
+ }
+ }
+ }
+
+ // private var dinnerType = ""
+ private var pageNo = 1
+ private val pageSize = 30
+
+ private lateinit var activity: SelectDishActivity
+
+ private var list: MutableList = mutableListOf()
+ private val dishAdapter by lazy {
+ DishShowAdapter(list = list).apply {
+ isStateViewEnable = true
+ setOnItemClickListener { adapter, view, position ->
+ val item = list[position]
+ if (item.isCooking) {
+ //烹饪中,跳到称熟重页面
+ context.startActivity {
+ putExtra(
+ SubmitDishActivity.FOOD_ITEM,
+ item as Serializable
+ )
+ }
+ return@setOnItemClickListener
+ }
+ context.startActivity {
+ putExtra(
+ SubmitDishActivity.FOOD_ITEM,
+ item as Serializable
+ )
+ }
+ }
+
+ }
+ }
+
+ private lateinit var binding: FragmentDishListBinding
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = FragmentDishListBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ activity = requireActivity() as SelectDishActivity
+ //toast("type=$type")
+ binding.rvDishList.run {
+ layoutManager =
+ LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
+ adapter = dishAdapter
+ val itemTouchHelper = ItemTouchHelper(SwipeCallback(dishAdapter) { position ->
+ if (list[position].isCooking.not()) {
+ activity.toast("只能删除烹饪中的菜品")
+ dishAdapter.notifyItemChanged(position)
+ return@SwipeCallback
+ }
+ activity.deleteCookFoodAndGoods(foodId = list[position].foodId ?: "") {
+ dishAdapter.removeAt(position)
+ activity.toast("已删除")
+ }
+ })
+ itemTouchHelper.attachToRecyclerView(this)
+ }
+ addViewListener()
+
+ pageNo = 1
+ activity.showLoading()
+ getDishList()
+ }
+
+ private fun addViewListener() {
+ binding.refreshLayout.run {
+ setEnableRefresh(true)
+ setEnableLoadMore(false)
+ setOnRefreshListener {
+ pageNo = 1
+ getDishList()
+ }
+ setOnLoadMoreListener {
+ getDishList()
+ }
+ }
+ }
+
+ fun getDishList(pageNo: Int, isCooking: Boolean) {
+ this.pageNo = pageNo
+ getDishList()
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ @Suppress("unchecked_cast")
+ fun getDishList() {
+ activity.showLoading()
+ val map = mapOf(
+// "foodName" to input,
+ "dinnerType" to activity.dinnerType,
+ "pageNo" to "$pageNo",
+ "pageSize" to "$pageSize",
+ "canteenId" to "0"
+ )
+ val sb = StringBuilder(UrlConfig.QUERY_FOOD_LIST).apply {
+ append("?")
+ map.forEach { (key, value) -> append("$key=$value&") }
+ }
+ sb.deleteCharAt(sb.length - 1)
+ HttpUtil.get(
+ url = sb.toString(),
+ doSuccess = {
+ binding.refreshLayout.run {
+ setEnableRefresh(true)
+ }
+ activity.delayDismissLoading()
+ finishRefresh()
+ val json = it.toJsonString()
+ val recordBean: FoodRecordBean? = json.toObject()
+ if (recordBean == null || recordBean.records.isNullOrEmpty()) {
+ //toast("暂未搜索到相关菜品信息")
+ if (pageNo == 1) {
+ loadEmptyView()
+ }
+ return@get
+ }
+ val records = recordBean.records
+ if (pageNo == 1) {
+ list.clear()
+ }
+ list.addAll(records!!)
+ dishAdapter.notifyDataSetChanged()
+ val isLoadMoreEnable = records.size >= pageSize
+ binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
+ if (isLoadMoreEnable) {
+ pageNo++
+ }
+ refreshLocalData(list)
+ }, doFailure = { code, msg ->
+ binding.refreshLayout.run {
+ setEnableRefresh(true)
+ }
+ toast(msg)
+ finishRefresh()
+ if (pageNo == 1) {
+ loadEmptyView()
+ }
+ activity.delayDismissLoading()
+ })
+ }
+
+ private var emptyViewBinding: LayoutEmptyViewBinding? = null
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun loadEmptyView() {
+ list.clear()
+ dishAdapter.notifyDataSetChanged()
+ if (emptyViewBinding == null) {
+ emptyViewBinding = LayoutEmptyViewBinding.inflate(
+ LayoutInflater.from(requireContext()),
+ binding.rvDishList,
+ false
+ )
+ }
+ emptyViewBinding!!.tvContent.text = "暂无数据"
+ emptyViewBinding!!.tvSubContent.text = "获取菜品数据失败,请检查网络设置或稍后重试"
+ dishAdapter.stateView = emptyViewBinding!!.root
+ //dishAdapter.setStateViewLayout(requireContext(), R.layout.layout_empty_view)
+ }
+
+ private fun finishRefresh() {
+ if (pageNo == 1) {
+ binding.refreshLayout.finishRefresh(1200)
+ } else {
+ binding.refreshLayout.finishLoadMore(1200)
+ }
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun refreshLocalData(list: MutableList) {
+ activity.getCookFoodList { cookFoodEntities ->
+ if (cookFoodEntities.isNullOrEmpty()) {
+ return@getCookFoodList
+ }
+ val tempList = mutableListOf()
+
+ cookFoodEntities.forEachIndexed { index, entity ->
+ val food = list.firstOrNull { it.foodId == entity.foodId }
+ if (food != null) {
+ food.isCooking = true
+ food.sort = index
+ tempList.add(food)
+ }
+ }
+ list.removeAll(tempList)
+ list.addAll(0, tempList)
+ dishAdapter.notifyDataSetChanged()
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishSamplingFragment.kt b/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishSamplingFragment.kt
new file mode 100644
index 0000000..a19fa65
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishSamplingFragment.kt
@@ -0,0 +1,187 @@
+package com.shuwei.dish.match.ui.fragment
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.aithings.Weigher
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.DishPartAdapter
+import com.shuwei.dish.match.databinding.FragmentDishSamplingBinding
+import com.shuwei.dish.match.dialog.BottomDialog
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.ui.FoodSearchActivity
+import com.shuwei.dish.match.ui.DishSamplingActivity
+import com.shuwei.dish.match.ui.SubmitDishActivity
+import com.shuwei.dish.match.utils.KeyboardUtil
+import com.shuwei.dish.match.utils.WeightUtil
+import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
+import com.shuwei.dish.match.utils.ext.clickWithDebounce
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toast
+import java.io.Serializable
+
+class DishSamplingFragment : Fragment() {
+
+ private val TAG = "DishSamplingFragment"
+
+ private lateinit var activity: DishSamplingActivity
+ private lateinit var binding: FragmentDishSamplingBinding
+
+ val list: MutableList = mutableListOf()
+
+ private var tempDishEntity: CookFoodGoodsEntity? = null
+
+ private var dishMaterialType = 1
+
+ private val dishAdapter by lazy {
+ DishPartAdapter(list).apply {
+ addOnItemChildClickListener(R.id.ivOperateIcon) { _, _, positon ->
+ //删除操作
+ removeAt(positon)
+ }
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentDishSamplingBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ activity = requireActivity() as DishSamplingActivity
+ addViewClickListener()
+ foodName = activity.foodName
+ binding.etInputDish.setText(foodName)
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun addViewClickListener() {
+ binding.rvDishPartList.run {
+ layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
+ adapter = dishAdapter
+ }
+ binding.tvInputDishType.run {
+ clickWithDebounce {
+ BottomDialog(goodsType = 0).show(activity) { item ->
+ val filterResult = list.firstOrNull { it.goodsName == item.goodsName }
+ if (filterResult != null) {
+ toast("不允许重复添加同一食材")
+ return@show
+ }
+ text = item.goodsName
+ tempDishEntity = CookFoodGoodsEntity().apply {
+ goodsId = item.goodsId
+ goodsName = item.goodsName
+
+ relateionType = item.relateionType?:0
+ goodsOrRelationCode = item.goodsOrRelationCode
+
+ // TODO: 待定
+ //allEdible = item.allEdible
+ }
+ }
+ }
+ }
+
+ binding.ivWeightClear.setOnClickListener {
+ Weigher.tareTwo(2)
+ }
+ WeightUtil.addWeightListener(getWeight = { address, state, weight ->
+ Log.d(TAG, "addViewClickListener: address=$address,state=$state,weight=$weight")
+ if (address == 2) {
+ tempDishEntity?.useWeight = weight
+ binding.tvDishPartWeight.text = "${weight}"
+ }
+ })
+ binding.ivWeightAdd.setOnClickListener {
+ if (tempDishEntity == null) {
+ activity.toast("请输入食材名称")
+ return@setOnClickListener
+ }
+ if (binding.rgSampling.checkedRadioButtonId == -1) {
+ activity.toast("请选择主辅材类型")
+ return@setOnClickListener
+ }
+ if (tempDishEntity!!.useWeight == null) {
+ activity.toast("请将食材放在称上称重")
+ return@setOnClickListener
+ }
+ tempDishEntity!!.apply {
+ isSamplingPage = true
+ materialType = dishMaterialType
+ }
+ val result = list.firstOrNull { it.goodsId == tempDishEntity!!.goodsId }
+ if (result != null) {
+ activity.toast("${result.goodsName}食材已添加,请勿重复操作")
+ return@setOnClickListener
+ }
+ list.add(tempDishEntity!!)
+ dishAdapter.notifyDataSetChanged()
+ tempDishEntity = null
+ binding.tvInputDishType.text = ""
+ binding.rgSampling.clearCheck()
+ }
+ binding.rgSampling.setOnCheckedChangeListener { group, checkedId ->
+ dishMaterialType = if (checkedId == R.id.rbDishTypeFirst) 1 else 2
+ }
+ binding.ivDishSearch.setOnClickListener { v ->
+ jumpSearch(v)
+ }
+ binding.btnCook.clickWithDebounce {
+ val showFoodName = binding.etInputDish.text.toString().trim()
+ if (showFoodName.isBlank()) {
+ toast("菜品名称为空")
+ return@clickWithDebounce
+ }
+ if (list.isEmpty()) {
+ toast("菜品构成信息未设置")
+ return@clickWithDebounce
+ }
+ val food = FoodRecord()
+ food.foodId = foodId
+ food.foodName = showFoodName
+ food.cookMode = 1
+ Log.d(TAG, "goToSubmit: goodsList:${list.toJsonString()}")
+ activity.startActivity {
+ putExtra(SubmitDishActivity.GOODS_LIST, list as Serializable)
+ putExtra(SubmitDishActivity.FOOD_ITEM, food as Serializable)
+ }
+ }
+ binding.etInputDish.let { v ->
+ v.addOnActionSearchListener {
+ jumpSearch(v)
+ }
+ }
+ }
+
+ private fun jumpSearch(v: View) {
+ activity.launch(Intent(activity, FoodSearchActivity::class.java).apply {
+ putExtra(FoodSearchActivity.FOOD_NAME, binding.etInputDish.text.toString().trim() )
+ }) { intent ->
+ intent?.let {
+ foodId = it.getStringExtra(FoodSearchActivity.FOOD_ID)
+ foodName = it.getStringExtra(FoodSearchActivity.FOOD_NAME)
+ binding.etInputDish.run {
+ setText(foodName)
+ setSelection(text.length)
+ }
+ }
+ }
+ KeyboardUtil.hideKeyboard(v.context, v)
+ }
+
+
+ private var foodId: String? = null
+ private var foodName: String? = null
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/fragment/SamplingListFragment.kt b/app/src/main/java/com/shuwei/dish/match/ui/fragment/SamplingListFragment.kt
new file mode 100644
index 0000000..69d22bf
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/fragment/SamplingListFragment.kt
@@ -0,0 +1,254 @@
+package com.shuwei.dish.match.ui.fragment
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.shuwei.dish.match.R
+import com.shuwei.dish.match.adapter.SamplingAdapter
+import com.shuwei.dish.match.databinding.FragmentSamplingListBinding
+import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
+
+import com.shuwei.dish.match.entity.FoodRecord
+import com.shuwei.dish.match.entity.FoodRecordBean
+import com.shuwei.dish.match.http.HttpUtil
+import com.shuwei.dish.match.http.UrlConfig
+import com.shuwei.dish.match.ui.DishSamplingActivity
+import com.shuwei.dish.match.ui.SamplingListActivity
+import com.shuwei.dish.match.ui.SubmitDishActivity
+import com.shuwei.dish.match.utils.DateTimeUtil
+import com.shuwei.dish.match.utils.SwipeCallback
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toJsonString
+import com.shuwei.dish.match.utils.ext.toObject
+import com.shuwei.dish.match.utils.ext.toast
+import java.io.Serializable
+
+class SamplingListFragment : Fragment() {
+
+ companion object {
+ private const val TAG = "SamplingListFragment"
+ }
+
+ private lateinit var activity: SamplingListActivity
+ private lateinit var binding: FragmentSamplingListBinding
+
+ private var list: MutableList = mutableListOf()
+ private val dishAdapter by lazy {
+ SamplingAdapter(list = list).apply {
+ isStateViewEnable = true
+ setOnItemClickListener { adapter, view, position ->
+ val item = list[position]
+ if (item.isCooking) {
+ //烹饪中,跳到称熟重页面
+ context.startActivity {
+ putExtra(
+ SubmitDishActivity.FOOD_ITEM,
+ item as Serializable
+ )
+ }
+ return@setOnItemClickListener
+ }
+ context.startActivity {
+ putExtra(DishSamplingActivity.FOOD_NAME, item.foodName)
+ }
+ }
+ }
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun initRecyclerView() {
+ binding.rvSamplingList.run {
+ layoutManager =
+ LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
+ adapter = dishAdapter
+ val itemTouchHelper = ItemTouchHelper(SwipeCallback(dishAdapter) { position ->
+ if (list[position].isCooking.not()) {
+ activity.toast("只能删除烹饪中的菜品")
+ dishAdapter.notifyItemChanged(position)
+ return@SwipeCallback
+ }
+ activity.deleteCookFoodAndGoods(foodId = list[position].foodId?:"") {
+ if (list.size > 1) {
+ dishAdapter.removeAt(position)
+ } else {
+ loadEmptyView()
+ }
+ activity.toast("已删除")
+ }
+ })
+ itemTouchHelper.attachToRecyclerView(this)
+ }
+ }
+
+ private fun addViewListener() {
+ binding.btnAddSampling.setOnClickListener {
+ activity.startActivity()
+ }
+ binding.refreshLayout.setOnRefreshListener {
+ pageNo = 1
+ getSamplingList()
+ }
+ binding.refreshLayout.setOnLoadMoreListener {
+ getSamplingList()
+ }
+ binding.dishRadioGroup.setOnCheckedChangeListener { group, checkedId ->
+ if (checkedId == R.id.rbCooking) {
+ refreshLocalData()
+ } else {
+ pageNo = 1
+ getSamplingList()
+ }
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentSamplingListBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ activity = requireActivity() as SamplingListActivity
+ initRecyclerView()
+ addViewListener()
+ refreshLocalData()
+ }
+
+ var pageNo = 1
+ private val pageSize = 30
+
+ @SuppressLint("NotifyDataSetChanged")
+ fun getSamplingList() {
+ activity.showLoading()
+ val map = mapOf(
+// "foodName" to input,
+ "pageNo" to "$pageNo",
+ "pageSize" to "$pageSize",
+ "canteenId" to "0"
+ )
+ val sb = StringBuilder(UrlConfig.SAMPLING_LIST).apply {
+ append("?")
+ map.forEach { (key, value) -> append("$key=$value&") }
+ }
+ sb.deleteCharAt(sb.length - 1)
+ HttpUtil.get(
+ url = sb.toString(),
+ doSuccess = {
+ binding.refreshLayout.run {
+ setEnableRefresh(true)
+ }
+ activity.delayDismissLoading()
+ finishRefresh()
+ val json = it.toJsonString()
+ val recordBean: FoodRecordBean? = json.toObject()
+ if (recordBean == null || recordBean.records.isNullOrEmpty()) {
+ //toast("暂未搜索到相关菜品信息")
+ if (pageNo == 1) {
+ loadEmptyView()
+ }
+ return@get
+ }
+ val records = recordBean.records
+ if (pageNo == 1) {
+ list.clear()
+ }
+ list.addAll(records!!)
+ dishAdapter.notifyDataSetChanged()
+ val isLoadMoreEnable = records.size >= pageSize
+ binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
+ binding.refreshLayout.setEnableRefresh(true)
+ if (isLoadMoreEnable) {
+ pageNo++
+ }
+ }, doFailure = { code, msg ->
+ binding.refreshLayout.run {
+ setEnableRefresh(true)
+ }
+ toast(msg)
+ finishRefresh()
+ binding.refreshLayout.setEnableRefresh(true)
+ activity.delayDismissLoading()
+ if (pageNo == 1) {
+ loadEmptyView()
+ }
+ })
+ }
+
+ private fun finishRefresh() {
+ if (pageNo == 1) {
+ binding.refreshLayout.finishRefresh(1200)
+ } else {
+ binding.refreshLayout.finishLoadMore(1200)
+ }
+ }
+
+ private var emptyViewBinding:LayoutEmptyViewBinding?=null
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun loadEmptyView() {
+ list.clear()
+ dishAdapter.notifyDataSetChanged()
+ if (emptyViewBinding == null) {
+ emptyViewBinding = LayoutEmptyViewBinding.inflate(LayoutInflater.from(requireContext()), binding.rvSamplingList, false)
+ }
+ emptyViewBinding!!.tvContent.text = "暂无数据"
+ emptyViewBinding!!.tvSubContent.text = "今日暂无采样数据,点击下方按钮新增采样"
+ dishAdapter.stateView = emptyViewBinding!!.root
+ //dishAdapter.setStateViewLayout(requireContext(), R.layout.layout_empty_view)
+
+ binding.refreshLayout.run {
+ setEnableRefresh(false)
+ setEnableLoadMore(false)
+ }
+ }
+
+ fun refreshPage(isCooking: Boolean) {
+ binding.dishRadioGroup.check(
+ if (isCooking) R.id.rbCooking else R.id.rbFinished
+ )
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ fun refreshLocalData() {
+ activity.showLoading()
+ //查询本地数据
+ activity.getCookFoodList { cookFoodEntities ->
+ activity.delayDismissLoading()
+ if (cookFoodEntities.isNullOrEmpty()) {
+ loadEmptyView()
+ return@getCookFoodList
+ }
+ val tempList = mutableListOf()
+
+ cookFoodEntities
+ .sortedByDescending { DateTimeUtil.convert(dateStr = it.createTime) }
+ .forEach { entity ->
+ tempList.add(FoodRecord().apply {
+ foodId = entity.foodId
+ foodName = entity.foodName
+ cookMode = 1
+ isCooking = true
+ })
+ }
+ list.clear()
+ list.addAll(tempList)
+ dishAdapter.notifyDataSetChanged()
+ binding.refreshLayout.run {
+ setEnableRefresh(false)
+ setEnableLoadMore(false)
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/ActivityManager.kt b/app/src/main/java/com/shuwei/dish/match/utils/ActivityManager.kt
new file mode 100644
index 0000000..5088a50
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/ActivityManager.kt
@@ -0,0 +1,52 @@
+package com.shuwei.dish.match.utils
+
+import android.app.Activity
+import java.util.Stack
+
+object ActivityManager {
+
+ private val activityStack = Stack()
+
+ // 添加Activity到栈
+ fun addActivity(activity: Activity) {
+ activityStack.add(activity)
+ }
+
+ // 移除指定Activity
+ fun removeActivity(activity: Activity) {
+ activityStack.remove(activity)
+ }
+
+ // 获取当前Activity
+ fun currentActivity(): Activity? {
+ return if (activityStack.isEmpty()) null else activityStack.lastElement()
+ }
+
+ // 结束指定Activity
+ fun finishActivity(activity: Activity) {
+ if (!activity.isFinishing) {
+ activity.finish()
+ }
+ }
+
+ // 结束所有Activity
+ fun finishAllActivity() {
+ activityStack.forEach {
+ if (!it.isFinishing) {
+ it.finish()
+ }
+ }
+ activityStack.clear()
+ }
+
+ // 退出应用程序
+ fun exitApp() {
+ finishAllActivity()
+ android.os.Process.killProcess(android.os.Process.myPid())
+ }
+
+ fun getActivityStack(): Stack{
+ return activityStack
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/DataUtil.kt b/app/src/main/java/com/shuwei/dish/match/utils/DataUtil.kt
new file mode 100644
index 0000000..4ef9bb1
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/DataUtil.kt
@@ -0,0 +1,28 @@
+package com.shuwei.dish.match.utils
+
+import android.util.SparseIntArray
+
+object DataUtil {
+
+ fun getWeighAddressArray(): SparseIntArray {
+ return SparseIntArray().apply {
+ put(0, 12)
+ put(1, 13)
+ put(2, 14)
+ put(3, 9)
+ put(4, 10)
+ put(5, 11)
+ put(6, 6)
+ put(7, 7)
+ put(8, 8)
+ put(9, 5)
+ put(12, 4)
+ put(10, 3)
+ put(11, 3)
+ put(13, 3)
+ put(14, 3)
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/DateTimeUtil.kt b/app/src/main/java/com/shuwei/dish/match/utils/DateTimeUtil.kt
new file mode 100644
index 0000000..12983d7
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/DateTimeUtil.kt
@@ -0,0 +1,32 @@
+package com.shuwei.dish.match.utils
+
+import java.time.LocalDateTime
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.util.Date
+
+
+object DateTimeUtil {
+
+ const val YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"
+
+ fun formatDateTime(dateTime: LocalDateTime, pattern: String = YYYY_MM_DD_HH_MM_SS): String {
+ val formatter = DateTimeFormatter.ofPattern(pattern)
+ return dateTime.format(formatter)
+ }
+
+ fun convert(dateStr: String, pattern: String = YYYY_MM_DD_HH_MM_SS): Date {
+ val formatter = DateTimeFormatter.ofPattern(pattern)
+ val ldt = LocalDateTime.parse(dateStr, formatter)
+ val zdt = ldt.atZone(ZoneId.systemDefault())
+ return Date.from(zdt.toInstant())
+ }
+
+ fun main() {
+ val now = LocalDateTime.now()
+ println("默认格式: ${formatDateTime(now)}")
+ println("自定义格式: ${formatDateTime(now, "yyyy年MM月dd日 HH时mm分ss秒")}")
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/DecimalAdapter.kt b/app/src/main/java/com/shuwei/dish/match/utils/DecimalAdapter.kt
new file mode 100644
index 0000000..7395bda
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/DecimalAdapter.kt
@@ -0,0 +1,26 @@
+package com.shuwei.dish.match.utils
+
+import com.google.gson.TypeAdapter
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonToken
+import com.google.gson.stream.JsonWriter
+
+class DecimalAdapter : TypeAdapter() {
+ override fun write(out: JsonWriter, value: Number) {
+// out.value(value.toString()) // 强制以字符串形式写入
+ out.value("$value") // 强制以字符串形式写入
+ }
+
+ override fun read(reader: JsonReader): Number {
+ return when (reader.peek()) {
+ JsonToken.NUMBER -> reader.nextDouble()
+ JsonToken.STRING -> reader.nextString().toDouble()
+ else -> 0.0
+ }
+ }
+}
+
+// 使用方式
+//val gson = GsonBuilder()
+// .registerTypeAdapter(Double::class.java, DecimalAdapter())
+// .create()
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/KeyboardUtil.kt b/app/src/main/java/com/shuwei/dish/match/utils/KeyboardUtil.kt
new file mode 100644
index 0000000..e978de1
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/KeyboardUtil.kt
@@ -0,0 +1,17 @@
+package com.shuwei.dish.match.utils
+
+import android.content.Context
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+
+
+object KeyboardUtil {
+
+ fun hideKeyboard(context: Context, view: View) {
+ val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ imm.hideSoftInputFromWindow(view.windowToken, 0)
+ view.clearFocus() // 清除焦点避免键盘再次弹出
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/LogUtil.kt b/app/src/main/java/com/shuwei/dish/match/utils/LogUtil.kt
new file mode 100644
index 0000000..2d3a6ea
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/LogUtil.kt
@@ -0,0 +1,11 @@
+package com.shuwei.dish.match.utils
+
+import android.util.Log
+
+//object LogUtil {
+//
+// fun d(tag: String, msg: String) {
+// Log.d(tag, msg)
+// }
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/SwipeCallback.kt b/app/src/main/java/com/shuwei/dish/match/utils/SwipeCallback.kt
new file mode 100644
index 0000000..cb1c384
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/SwipeCallback.kt
@@ -0,0 +1,62 @@
+package com.shuwei.dish.match.utils
+
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.RecyclerView
+import com.chad.library.adapter4.BaseQuickAdapter
+import com.chad.library.adapter4.viewholder.QuickViewHolder
+import com.shuwei.dish.match.adapter.DishPartAdapter
+import com.shuwei.dish.match.adapter.DishShowAdapter
+import com.shuwei.dish.match.adapter.SamplingAdapter
+
+class SwipeCallback(
+ private val adapter: BaseQuickAdapter<*,*>,
+ private val callback: (position: Int) -> Unit = {}
+) :
+ ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
+ override fun onMove(
+ recyclerView: RecyclerView,
+ viewHolder: RecyclerView.ViewHolder,
+ target: RecyclerView.ViewHolder
+ ): Boolean {
+ return false // 不允许拖动,只允许滑动删除
+ }
+
+ override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
+ val position = viewHolder.getBindingAdapterPosition()
+ callback(position)
+ }
+
+ override fun getMovementFlags(
+ recyclerView: RecyclerView,
+ viewHolder: RecyclerView.ViewHolder
+ ): Int {
+ val position = viewHolder.getBindingAdapterPosition()
+ // 默认的拖动和滑动方向
+ val dragFlags = 0
+ // ItemTouchHelper.UP or ItemTouchHelper.DOWN
+ var swipeFlags = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
+
+ if (adapter is SamplingAdapter) {
+ if (!adapter.items[position].isCooking) {
+ swipeFlags = 0
+ }
+ } else if (adapter is DishShowAdapter) {
+ if (!adapter.items[position].isCooking) {
+ swipeFlags = 0
+ }
+ } else if (adapter is DishPartAdapter) {
+ if (!adapter.items[position].isNewDishType) {
+ swipeFlags = 0
+ }
+ }
+
+ // 根据viewHolder的逻辑判断是否允许滑动
+ val count = recyclerView.adapter?.itemCount ?:0
+ //BaseQuickAdapter中空布局使用的ViewHolder是这个import com.chad.library.adapter4.viewholder.StateLayoutVH
+ if (count == 1 && viewHolder !is QuickViewHolder) {
+ swipeFlags = 0 // 不允许滑动
+ }
+ return makeMovementFlags(dragFlags, swipeFlags)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/ToastUtil.kt b/app/src/main/java/com/shuwei/dish/match/utils/ToastUtil.kt
new file mode 100644
index 0000000..e4e5bbe
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/ToastUtil.kt
@@ -0,0 +1,28 @@
+package com.shuwei.dish.match.utils
+
+import android.content.Context
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.TextView
+import android.widget.Toast
+import com.shuwei.dish.match.R
+
+
+object ToastUtil {
+
+ fun show(context: Context, message: String, duration:Int = Toast.LENGTH_SHORT) {
+ val inflater = LayoutInflater.from(context)
+ val layout: View = inflater.inflate(R.layout.custom_toast, null)
+ val textView = layout.findViewById(R.id.tvMessage)
+ textView.text = message
+
+ val toast = Toast(context)
+ toast.view = layout // 设置自定义视图
+ toast.setGravity(Gravity.CENTER, 0, 0) // 调整位置居中显示
+ toast.setDuration(duration)
+ toast.show()
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/WeightUtil.kt b/app/src/main/java/com/shuwei/dish/match/utils/WeightUtil.kt
new file mode 100644
index 0000000..531843f
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/WeightUtil.kt
@@ -0,0 +1,148 @@
+package com.shuwei.dish.match.utils
+
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import com.aithings.Weigher
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.utils.ext.toast
+import com.wabon.wbintelligenthardwaresdk.api.SensorScale
+
+object WeightUtil {
+
+ fun connect(initCallback: (connect: Boolean) -> Unit) {
+ Weigher.setListener(object : WeightListenerImpl() {
+ override fun onInit(connect: Boolean) {
+ initCallback(connect)
+ Log.d("WeightUtil", "connect=$connect")
+ }
+
+ override fun onZero() {
+ Log.d("WeightUtil", "zero ok")
+ }
+
+ override fun onTare() {
+ Log.d("WeightUtil", "去皮置零操作成功")
+ }
+
+ override fun onSetIdentify() {
+ Log.d("WeightUtil", "鉴别率设置操作成功")
+ }
+
+ override fun onGetWeight(address: Int, state: Int, weight: Int) {
+ runOnUiThread {
+ val stateStr = when (state) {
+ SensorScale.STATE_STABLE -> "稳定"
+ SensorScale.STATE_UNSTABLE -> "不稳定"
+ SensorScale.STATE_OVER_WEIGHT -> "量程溢出"
+ else -> ""
+ }
+ val result1 = String.format("$stateStr 重量:%s kg", weight / 1000f)
+ Log.d("WeightUtil", "ttlReturn, address:$address,$result1")
+ }
+ }
+
+ override fun onReadIdentify(rate: Int) {
+ Log.d("WeightUtil", "读取鉴别率成功:rate=$rate")
+ }
+
+ override fun onFail(errCode: Int) {
+ val str = when (errCode) {
+ Weigher.ERR_001 -> "电子称未初始化"
+ Weigher.ERR_002 -> "开机零位异常"
+ Weigher.ERR_003 -> "传感器故障"
+ Weigher.ERR_004 -> "鉴别率超出范围"
+ Weigher.ERR_PCB_NOT_SUPPORT -> "主板不支持, " + Build.MODEL
+ else -> ""
+ }
+ Log.d("WeightUtil", str)
+ }
+
+ override fun onFastFilter() {
+ Log.d("WeightUtil", "快速滤波设置成功")
+ }
+
+ override fun onReadParam() {
+ Log.d("WeightUtil", "prepare ok")
+ }
+
+ override fun onRangCal() {
+ Log.d("WeightUtil", "rang cal ok")
+ }
+
+ override fun onSetParam() {
+ Log.d("WeightUtil", "onSetParam")
+ }
+ })
+ }
+
+ private fun runOnUiThread(action: () -> Unit) {
+ Handler(Looper.getMainLooper()).post {
+ action()
+ }
+ }
+
+ fun addWeightListener(
+ zero: (() -> Unit) = {},
+ getWeight: ((address: Int, state: Int, weight: Int) -> Unit) = { _, _, _ -> }
+ ) {
+ Weigher.setListener(object : WeightListenerImpl() {
+ override fun onZero() {
+ zero()
+ }
+
+ override fun onGetWeight(address: Int, state: Int, weight: Int) {
+ getWeight(address, state, weight)
+ }
+ })
+ }
+
+}
+
+open class WeightListenerImpl : Weigher.Listener {
+ override fun onInit(connect: Boolean) {
+
+ }
+
+ override fun onZero() {
+
+ }
+
+ override fun onTare() {
+
+ }
+
+ override fun onSetIdentify() {
+
+ }
+
+ override fun onGetWeight(address: Int, state: Int, weight: Int) {
+
+ }
+
+ override fun onReadIdentify(rate: Int) {
+
+ }
+
+ override fun onFail(errCode: Int) {
+
+ }
+
+ override fun onFastFilter() {
+
+ }
+
+ override fun onReadParam() {
+
+ }
+
+ override fun onRangCal() {
+
+ }
+
+ override fun onSetParam() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/ext/Common.kt b/app/src/main/java/com/shuwei/dish/match/utils/ext/Common.kt
new file mode 100644
index 0000000..97c51d1
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/ext/Common.kt
@@ -0,0 +1,175 @@
+package com.shuwei.dish.match.utils.ext
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.content.res.Resources
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.widget.EditText
+import android.widget.Toast
+import androidx.core.app.ActivityOptionsCompat
+import androidx.fragment.app.Fragment
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.shuwei.dish.match.utils.ToastUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+fun Context.toast(
+ message: String?,
+ duration: Int = Toast.LENGTH_SHORT,
+) {
+ if (message.isNullOrBlank()) {
+ return
+ }
+ //Toast.makeText(this, message, duration).show()
+ ToastUtil.show(this, message, duration)
+}
+
+fun Fragment.toast(
+ message: String?,
+ duration: Int = 2000
+) {
+ activity?.toast(message, duration)
+}
+
+//fun Fragment.toast(
+// message: String?,
+// duration: Int = 2000
+//) {
+// if (isAdded.not()) {
+// return
+// }
+// CustomToast(
+// activity = requireActivity(),
+// message = message,
+// duration = duration
+// ).show()
+//}
+//
+//public fun BaseActivity.toast(message: String?, duration: Int = 2000) {
+// CustomToast(
+// activity = this,
+// message = message,
+// duration = duration
+// ).show()
+//}
+
+fun View.visible() {
+ visibility = View.VISIBLE
+}
+
+fun View.invisible() {
+ visibility = View.INVISIBLE
+}
+
+fun View.gone() {
+ visibility = View.GONE
+}
+
+inline fun Context.startActivity(
+ bundle: Bundle? = null,
+ options: ActivityOptionsCompat? = null
+) {
+ Intent(this, T::class.java).apply {
+ bundle?.let { putExtras(it) }
+ if (options != null && this@startActivity is Activity) {
+ startActivity(this, options.toBundle())
+ } else {
+ startActivity(this)
+ }
+ }
+}
+
+inline fun Context.startActivity(
+ block: Intent.() -> Unit = {}
+) {
+ Intent(this, T::class.java).apply {
+ block()
+ startActivity(this)
+ }
+}
+
+//inline fun Context.startActivity(action:(bundle: Bundle)-> Unit) {
+// Intent(this, T::class.java).apply {
+// action(Bundle())
+// startActivity(this)
+// }
+//}
+
+inline fun String.toType(gson: Gson? = null, typeToken: TypeToken): T {
+ return (gson ?: Gson()).fromJson(this, typeToken.type)
+}
+
+inline fun String.toObject(gson: Gson? = null): T {
+ return (gson ?: Gson()).fromJson(this, T::class.java)
+}
+
+fun Any?.toJsonString(gson: Gson? = null): String {
+ return (gson ?: Gson()).toJson(this) ?: ""
+}
+
+@SuppressLint("ApplySharedPref")
+inline fun SharedPreferences.edit(
+ commit: Boolean = false,
+ action: SharedPreferences.Editor.() -> Unit
+) {
+ val editor = edit()
+ action(editor)
+ if (commit) editor.commit() else editor.apply()
+}
+
+fun SharedPreferences.put(vararg pairs: Pair) {
+ edit {
+ pairs.forEach { (key, value) ->
+ when (value) {
+ is Int -> putInt(key, value)
+ is String -> putString(key, value)
+ is Boolean -> putBoolean(key, value)
+ is Float -> putFloat(key, value)
+ is Long -> putLong(key, value)
+ }
+ }
+ }
+}
+
+val Float.dp: Float
+ get() = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ this,
+ Resources.getSystem().displayMetrics
+ )
+
+val Int.dp: Int
+ get() = this.toFloat().dp.toInt()
+
+fun EditText.addOnActionSearchListener(searchCallback: () -> Unit) {
+ setOnEditorActionListener { v, actionId, event ->
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ // 处理搜索逻辑
+ searchCallback()
+ return@setOnEditorActionListener true // 阻止事件继续传递
+ }
+ return@setOnEditorActionListener false
+ }
+}
+
+
+fun View.clickWithDebounce(delay: Long = 500, action: () -> Unit) {
+ var job: Job? = null
+ setOnClickListener {
+ job?.cancel()
+ job = CoroutineScope(Dispatchers.Main).launch {
+ delay(delay)
+ action()
+ }
+ }
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/utils/ext/SpannableExt.kt b/app/src/main/java/com/shuwei/dish/match/utils/ext/SpannableExt.kt
new file mode 100644
index 0000000..bfee7e8
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/utils/ext/SpannableExt.kt
@@ -0,0 +1,25 @@
+package com.shuwei.dish.match.utils.ext
+
+import android.text.SpannableString
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+
+
+inline fun buildSpannableString(builderAction: SpannableStringBuilder.() -> Unit): SpannableStringBuilder {
+ return SpannableStringBuilder().apply(builderAction)
+}
+
+fun SpannableStringBuilder.appendText(text: String, vararg spans: Any): SpannableStringBuilder {
+ val start = length
+ append(text)
+ spans.forEach { span ->
+ setSpan(span, start, length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
+ }
+ return this
+}
+
+fun SpannableStringBuilder.withSpan(span: Any, block: SpannableStringBuilder.() -> Unit) {
+ val start = length
+ block()
+ setSpan(span, start, length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/viewmodel/AppViewModel.kt b/app/src/main/java/com/shuwei/dish/match/viewmodel/AppViewModel.kt
new file mode 100644
index 0000000..d7eff06
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/viewmodel/AppViewModel.kt
@@ -0,0 +1,183 @@
+package com.shuwei.dish.match.viewmodel
+
+import android.util.Log
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.shuwei.dish.match.base.BaseApp
+import com.shuwei.dish.match.db.AppRepository
+import com.shuwei.dish.match.entity.CookFoodEntity
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.entity.SeasoningEntity
+import com.shuwei.dish.match.utils.ext.toast
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlin.collections.forEach
+
+class AppViewModel(private val rep: AppRepository) : ViewModel() {
+
+ fun updateCookFood(entity: CookFoodEntity) {
+ viewModelScope.launch {
+ rep.updateCookFood(entity)
+ }
+ }
+
+ fun getCookFoodById(foodId: String, cookMode: Int, action: (CookFoodEntity?) -> Unit) {
+ viewModelScope.launch {
+ val data = rep.getCookFoodById(foodId, cookMode)
+ action(data)
+ }
+ }
+
+ fun getCookFoodList(cookMode: Int, action: (MutableList?) -> Unit) {
+ viewModelScope.launch {
+ val data = rep.getCookFoodList(cookMode)
+ action(data)
+ }
+ }
+
+ fun countCookFood(cookMode: Int, action: (Int) -> Unit) {
+ viewModelScope.launch {
+ val count = rep.countCookFood(cookMode)
+ action(count)
+ }
+ }
+
+ fun saveCookFood(cookMode: Int, entity: CookFoodEntity) {
+ viewModelScope.launch {
+ val data = rep.getCookFoodById(entity.foodId, cookMode)
+ if (data == null) {
+ rep.insertCookFood(entity)
+ return@launch
+ }
+ rep.updateCookFood(entity)
+ }
+ }
+
+ fun saveCookFoodAndGoods(
+ cookMode: Int,
+ entity: CookFoodEntity,
+ list: MutableList?,
+ onFinish: () -> Unit
+ ) {
+ viewModelScope.launch {
+ val data = rep.getCookFoodById(entity.foodId, cookMode)
+ if (data != null) {
+ //存在数据删除
+ rep.deleteCookFood(entity.foodId, cookMode)
+ rep.deleteCookFoodGoodsList(entity.foodId)
+ }
+ //重新保存数据
+ rep.insertCookFood(entity)
+ list?.let { rep.insertGoodsList(it) }
+ onFinish()
+ }
+ }
+
+ fun deleteCookFoodAndGoods(
+ cookMode: Int,
+ foodId: String,
+ onFinish: () -> Unit
+ ) {
+ viewModelScope.launch {
+ rep.deleteCookFood(foodId = foodId, cookMode = cookMode)
+ rep.deleteCookFoodGoodsList(foodId)
+ onFinish()
+ }
+ }
+
+ //--------------------------------------------------------------------------------------------------------
+
+
+ fun getCookFoodGoodsList(
+ foodId: String,
+ action: (list: MutableList) -> Unit
+ ) {
+ viewModelScope.launch {
+ val list = rep.getCookFoodGoodsList(foodId)
+ action(list)
+ }
+ }
+
+ fun updateGoods(entity: CookFoodGoodsEntity) {
+ viewModelScope.launch {
+ rep.updateGoods(entity)
+ }
+ }
+
+ fun saveCookFoodGoods(list: MutableList) {
+ viewModelScope.launch {
+ val foodId = list[0].foodId
+ val data: MutableList? =
+ rep.getCookFoodGoodsList(foodId!!)
+ if (data.isNullOrEmpty()) {
+ rep.insertGoodsList(list)
+ return@launch
+ }
+ val localDbSeasoningList = rep.getCookFoodGoodsListByType(foodId, 3)
+ localDbSeasoningList.forEach {
+ it.isDel = 1
+ //更新本地调料数据为已删除的状态
+ rep.updateGoods(it)
+ }
+ //筛选出调料数据保存,主辅材不会变更不需要再次处理
+ val saveSeasoningList = list.filter { it.materialType == 3 }
+ rep.insertGoodsList(saveSeasoningList.toMutableList())
+ }
+ }
+
+ //--------------------------------------------------------------------------------------------------------
+
+ fun addSeasoning(list: MutableList, callback: () -> Unit) {
+ viewModelScope.launch {
+ rep.deleteBatch()
+ rep.insertSeasoningList(items = list)
+ callback()
+ }
+ }
+
+ private var isProcessing = false
+ fun loadSeasoning(action: (list: MutableList) -> Unit) {
+ viewModelScope.launch {
+ if (isProcessing) return@launch
+ isProcessing = true
+ rep.getAllStream().collect { list ->
+ action(list)
+ isProcessing = false
+ }
+ }
+ }
+
+ fun deleteEmptySeasoning() {
+ viewModelScope.launch {
+ rep.deleteEmptySeasoning()
+ }
+ }
+ fun deleteAll() {
+ viewModelScope.launch {
+ rep.deleteBatch()
+ }
+ }
+
+ fun updateAll(list: MutableList) {
+ viewModelScope.launch {
+ list.forEach {
+ rep.updateSeasoning(it)
+ }
+ }
+ }
+
+ fun saveSeasoning(entity: SeasoningEntity, block:()-> Unit) {
+ viewModelScope.launch {
+ val seasoning = rep.getSeasoningBySort(entity.sort)
+ if (seasoning == null) {
+ rep.insertSeasoning(entity)
+ block()
+ return@launch
+ }
+ rep.updateSeasoning(entity.also { it.id = seasoning.id })
+ block()
+ }
+ }
+
+ //--------------------------------------------------------------------------------------------------------
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/viewmodel/CookFoodGoodsViewModel.kt b/app/src/main/java/com/shuwei/dish/match/viewmodel/CookFoodGoodsViewModel.kt
new file mode 100644
index 0000000..5322ca2
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/viewmodel/CookFoodGoodsViewModel.kt
@@ -0,0 +1,42 @@
+//package com.shuwei.dish.match.viewmodel
+//
+//import androidx.lifecycle.ViewModel
+//import androidx.lifecycle.viewModelScope
+//import com.shuwei.dish.match.db.CookFoodGoodsRepository
+//import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+//import kotlinx.coroutines.launch
+//
+//class CookFoodGoodsViewModel(private val rep: CookFoodGoodsRepository) : ViewModel() {
+//
+// fun getCookFoodGoodsList(
+// foodId: String,
+// action: (list: MutableList) -> Unit
+// ) {
+// viewModelScope.launch {
+// val list = rep.cookFoodGoodsDao.getCookFoodGoodsList(foodId)
+// action(list)
+// }
+// }
+//
+// fun saveCookFoodGoods(list: MutableList) {
+// viewModelScope.launch {
+// val foodId = list[0].foodId
+// val data: MutableList? =
+// rep.cookFoodGoodsDao.getCookFoodGoodsList(foodId!!)
+// if (data.isNullOrEmpty()) {
+// rep.cookFoodGoodsDao.insertAll(list)
+// return@launch
+// }
+// val localDbSeasoningList = rep.cookFoodGoodsDao.getCookFoodGoodsListByType(foodId, 3)
+// localDbSeasoningList.forEach {
+// it.isDel = 1
+// //更新本地调料数据为已删除的状态
+// rep.cookFoodGoodsDao.update(it)
+// }
+// //筛选出调料数据保存,主辅材不会变更不需要再次处理
+// val saveSeasoningList = list.filter { it.materialType == 3 }
+// rep.cookFoodGoodsDao.insertAll(saveSeasoningList.toMutableList())
+// }
+// }
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/viewmodel/CookFoodViewModel.kt b/app/src/main/java/com/shuwei/dish/match/viewmodel/CookFoodViewModel.kt
new file mode 100644
index 0000000..a6c8468
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/viewmodel/CookFoodViewModel.kt
@@ -0,0 +1,44 @@
+//package com.shuwei.dish.match.viewmodel
+//
+//import androidx.lifecycle.ViewModel
+//import androidx.lifecycle.viewModelScope
+//import com.shuwei.dish.match.db.CookFoodRepository
+//import com.shuwei.dish.match.entity.CookFoodEntity
+//import kotlinx.coroutines.launch
+//
+//class CookFoodViewModel(private val rep: CookFoodRepository) : ViewModel() {
+//
+// fun getCookFoodById(foodId: String, cookMode: Int, action: (CookFoodEntity?) -> Unit) {
+// viewModelScope.launch {
+// val data = rep.cookFoodDao.getCookFoodById(foodId, cookMode)
+// action(data)
+// }
+// }
+//
+// fun getCookFoodList(cookMode: Int, action: (MutableList?) -> Unit) {
+// viewModelScope.launch {
+// val data = rep.cookFoodDao.getCookFoodList(cookMode)
+// action(data)
+// }
+// }
+//
+// fun countCookFood(cookMode: Int, action: (Int) -> Unit) {
+// viewModelScope.launch {
+// val count = rep.cookFoodDao.countCookFood(cookMode)
+// action(count)
+// }
+// }
+//
+// fun saveCookFood(cookMode: Int, entity: CookFoodEntity) {
+// viewModelScope.launch {
+// val data = rep.cookFoodDao.getCookFoodById(entity.foodId, cookMode)
+// if (data == null) {
+// rep.cookFoodDao.insert(entity)
+// return@launch
+// }
+// rep.cookFoodDao.update(entity)
+//
+// }
+// }
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/viewmodel/DeviceSettingViewModel.kt b/app/src/main/java/com/shuwei/dish/match/viewmodel/DeviceSettingViewModel.kt
new file mode 100644
index 0000000..cbb8e0d
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/viewmodel/DeviceSettingViewModel.kt
@@ -0,0 +1,47 @@
+//package com.shuwei.dish.match.viewmodel
+//
+//import androidx.lifecycle.ViewModel
+//import androidx.lifecycle.viewModelScope
+//import com.shuwei.dish.match.db.SeasoningRepository
+//import com.shuwei.dish.match.entity.SeasoningEntity
+//import kotlinx.coroutines.delay
+//import kotlinx.coroutines.launch
+//
+//class DeviceSettingViewModel(private val rep: SeasoningRepository) : ViewModel() {
+// fun addSeasoning(list: MutableList, callback:()-> Unit) {
+// viewModelScope.launch {
+// rep.seasoningDao.deleteBatch()
+// delay(500)
+// val rows: Array? = rep.seasoningDao.insertAll(items = list)
+// if (rows.isNullOrEmpty().not()) {
+// callback()
+// }
+// }
+// }
+//
+// private var isProcessing = false
+// fun loadSeasoning(action: (list: MutableList) -> Unit) {
+// viewModelScope.launch {
+// if (isProcessing) return@launch
+// isProcessing = true
+// rep.seasoningDao.getAllStream().collect { list ->
+// action(list)
+// isProcessing = false
+// }
+// }
+// }
+//
+// fun deleteAll() {
+// viewModelScope.launch {
+// rep.seasoningDao.deleteBatch()
+// }
+// }
+//
+// fun updateAll(list: MutableList) {
+// viewModelScope.launch {
+// list.forEach {
+// rep.seasoningDao.update(it)
+// }
+// }
+// }
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/viewmodel/SubmitDishViewModel.kt b/app/src/main/java/com/shuwei/dish/match/viewmodel/SubmitDishViewModel.kt
new file mode 100644
index 0000000..2919895
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/viewmodel/SubmitDishViewModel.kt
@@ -0,0 +1,24 @@
+//package com.shuwei.dish.match.viewmodel
+//
+//import androidx.lifecycle.ViewModel
+//import androidx.lifecycle.viewModelScope
+//import com.shuwei.dish.match.db.SeasoningRepository
+//import com.shuwei.dish.match.entity.CookFoodEntity
+//import com.shuwei.dish.match.entity.SeasoningEntity
+//import kotlinx.coroutines.launch
+//
+//class SubmitDishViewModel(private val rep: SeasoningRepository) : ViewModel() {
+//
+// private var isProcessing = false
+// fun loadSeasoning(action: (list: MutableList) -> Unit) {
+// viewModelScope.launch {
+// if (isProcessing) return@launch
+// isProcessing = true
+// rep.seasoningDao.getAllStream().collect { list ->
+// action(list)
+// isProcessing = false
+// }
+// }
+// }
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/shuwei/dish/match/viewmodel/factory/VMFactory.kt b/app/src/main/java/com/shuwei/dish/match/viewmodel/factory/VMFactory.kt
new file mode 100644
index 0000000..1ca32fc
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/viewmodel/factory/VMFactory.kt
@@ -0,0 +1,43 @@
+package com.shuwei.dish.match.viewmodel.factory
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.shuwei.dish.match.db.AppRepository
+import com.shuwei.dish.match.viewmodel.AppViewModel
+
+@Suppress("UNCHECKED_CAST")
+class AppFactory(private val repo: AppRepository) : ViewModelProvider.Factory {
+ override fun create(modelClass: Class): T {
+ return AppViewModel(repo) as T
+ }
+}
+
+//
+//@Suppress("UNCHECKED_CAST")
+//class DeviceSettingFactory(private val repo: SeasoningRepository) : ViewModelProvider.Factory {
+// override fun create(modelClass: Class): T {
+// return DeviceSettingViewModel(repo) as T
+// }
+//}
+//
+////@Suppress("UNCHECKED_CAST")
+////class SubmitDishFactory(private val repo: SeasoningRepository) : ViewModelProvider.Factory {
+//// override fun create(modelClass: Class): T {
+//// return SubmitDishViewModel(repo) as T
+//// }
+////}
+//
+//@Suppress("UNCHECKED_CAST")
+//class CookFoodFactory(private val repo: CookFoodRepository) : ViewModelProvider.Factory {
+// override fun create(modelClass: Class): T {
+// return CookFoodViewModel(repo) as T
+// }
+//}
+//
+//@Suppress("UNCHECKED_CAST")
+//class CookFoodGoodsFactory(private val repo: CookFoodGoodsRepository) : ViewModelProvider.Factory {
+// override fun create(modelClass: Class): T {
+// return CookFoodGoodsViewModel(repo) as T
+// }
+//}
+
diff --git a/app/src/main/res/color/breakfast_font.xml b/app/src/main/res/color/breakfast_font.xml
new file mode 100644
index 0000000..197f200
--- /dev/null
+++ b/app/src/main/res/color/breakfast_font.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/color/dish_type_font.xml b/app/src/main/res/color/dish_type_font.xml
new file mode 100644
index 0000000..35199a3
--- /dev/null
+++ b/app/src/main/res/color/dish_type_font.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-xxxhdpi/bg_home_page.png b/app/src/main/res/drawable-xxxhdpi/bg_home_page.png
new file mode 100644
index 0000000..cab6ff2
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_home_page.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_right.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_right.png
new file mode 100644
index 0000000..324a23b
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_right.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_back.png b/app/src/main/res/drawable-xxxhdpi/ic_back.png
new file mode 100644
index 0000000..e01068e
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_back.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_check_false.png b/app/src/main/res/drawable-xxxhdpi/ic_check_false.png
new file mode 100644
index 0000000..7b02c5c
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_check_false.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_check_true.png b/app/src/main/res/drawable-xxxhdpi/ic_check_true.png
new file mode 100644
index 0000000..f5b5b6d
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_check_true.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_delete.png b/app/src/main/res/drawable-xxxhdpi/ic_delete.png
new file mode 100644
index 0000000..f5a14db
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_delete.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_dish_disable.png b/app/src/main/res/drawable-xxxhdpi/ic_dish_disable.png
new file mode 100644
index 0000000..fc92f86
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_dish_disable.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_dish_selected.png b/app/src/main/res/drawable-xxxhdpi/ic_dish_selected.png
new file mode 100644
index 0000000..3ec01f4
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_dish_selected.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_dish_unselected.png b/app/src/main/res/drawable-xxxhdpi/ic_dish_unselected.png
new file mode 100644
index 0000000..6754bbc
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_dish_unselected.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_food_add.png b/app/src/main/res/drawable-xxxhdpi/ic_food_add.png
new file mode 100644
index 0000000..92002b6
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_food_add.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_lock.png b/app/src/main/res/drawable-xxxhdpi/ic_lock.png
new file mode 100644
index 0000000..93212d4
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_lock.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_mode_cook.png b/app/src/main/res/drawable-xxxhdpi/ic_mode_cook.png
new file mode 100644
index 0000000..0ac4e9e
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_mode_cook.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_mode_quality.png b/app/src/main/res/drawable-xxxhdpi/ic_mode_quality.png
new file mode 100644
index 0000000..373b64b
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_mode_quality.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_mode_sampling.png b/app/src/main/res/drawable-xxxhdpi/ic_mode_sampling.png
new file mode 100644
index 0000000..be50c41
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_mode_sampling.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_search.png b/app/src/main/res/drawable-xxxhdpi/ic_search.png
new file mode 100644
index 0000000..cbad3e4
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_search.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_search_gray.png b/app/src/main/res/drawable-xxxhdpi/ic_search_gray.png
new file mode 100644
index 0000000..6aa389f
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_search_gray.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_search_green.png b/app/src/main/res/drawable-xxxhdpi/ic_search_green.png
new file mode 100644
index 0000000..de61c79
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_search_green.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_setting.png b/app/src/main/res/drawable-xxxhdpi/ic_setting.png
new file mode 100644
index 0000000..5631615
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_setting.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_weight_add.png b/app/src/main/res/drawable-xxxhdpi/ic_weight_add.png
new file mode 100644
index 0000000..73ff568
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_weight_add.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_weight_clear.png b/app/src/main/res/drawable-xxxhdpi/ic_weight_clear.png
new file mode 100644
index 0000000..6573802
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_weight_clear.png differ
diff --git a/app/src/main/res/drawable/bg_other_page.xml b/app/src/main/res/drawable/bg_other_page.xml
new file mode 100644
index 0000000..8ef2112
--- /dev/null
+++ b/app/src/main/res/drawable/bg_other_page.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_rounded_top.xml b/app/src/main/res/drawable/bg_rounded_top.xml
new file mode 100644
index 0000000..0f8bc89
--- /dev/null
+++ b/app/src/main/res/drawable/bg_rounded_top.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/breakfast_bg.xml b/app/src/main/res/drawable/breakfast_bg.xml
new file mode 100644
index 0000000..af19580
--- /dev/null
+++ b/app/src/main/res/drawable/breakfast_bg.xml
@@ -0,0 +1,15 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/mode_select.xml b/app/src/main/res/drawable/mode_select.xml
new file mode 100644
index 0000000..4d37800
--- /dev/null
+++ b/app/src/main/res/drawable/mode_select.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ripple_effect_green.xml b/app/src/main/res/drawable/ripple_effect_green.xml
new file mode 100644
index 0000000..98e073c
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_effect_green.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ripple_effect_light.xml b/app/src/main/res/drawable/ripple_effect_light.xml
new file mode 100644
index 0000000..0c723c6
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_effect_light.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ripple_effect_light2.xml b/app/src/main/res/drawable/ripple_effect_light2.xml
new file mode 100644
index 0000000..dbe43a0
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_effect_light2.xml
@@ -0,0 +1,10 @@
+
+
+ -
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/selector_dish_type.xml b/app/src/main/res/drawable/selector_dish_type.xml
new file mode 100644
index 0000000..7998612
--- /dev/null
+++ b/app/src/main/res/drawable/selector_dish_type.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_text_cell.xml b/app/src/main/res/drawable/selector_text_cell.xml
new file mode 100644
index 0000000..1f07d0a
--- /dev/null
+++ b/app/src/main/res/drawable/selector_text_cell.xml
@@ -0,0 +1,17 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_dialog.xml b/app/src/main/res/drawable/shape_dialog.xml
new file mode 100644
index 0000000..c7e4546
--- /dev/null
+++ b/app/src/main/res/drawable/shape_dialog.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray_dc_5.xml b/app/src/main/res/drawable/shape_gray_dc_5.xml
new file mode 100644
index 0000000..633252c
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray_dc_5.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray_f8_15.xml b/app/src/main/res/drawable/shape_gray_f8_15.xml
new file mode 100644
index 0000000..9319794
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray_f8_15.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_green_15_corners.xml b/app/src/main/res/drawable/shape_green_15_corners.xml
new file mode 100644
index 0000000..4b0ff0e
--- /dev/null
+++ b/app/src/main/res/drawable/shape_green_15_corners.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_green_5_corners.xml b/app/src/main/res/drawable/shape_green_5_corners.xml
new file mode 100644
index 0000000..ad634e9
--- /dev/null
+++ b/app/src/main/res/drawable/shape_green_5_corners.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_green_bg.xml b/app/src/main/res/drawable/shape_green_bg.xml
new file mode 100644
index 0000000..1f9fd2f
--- /dev/null
+++ b/app/src/main/res/drawable/shape_green_bg.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_green_stroke.xml b/app/src/main/res/drawable/shape_green_stroke.xml
new file mode 100644
index 0000000..dba4385
--- /dev/null
+++ b/app/src/main/res/drawable/shape_green_stroke.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_item_cook_dish.xml b/app/src/main/res/drawable/shape_item_cook_dish.xml
new file mode 100644
index 0000000..723b9b6
--- /dev/null
+++ b/app/src/main/res/drawable/shape_item_cook_dish.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_12_corners.xml b/app/src/main/res/drawable/shape_white_12_corners.xml
new file mode 100644
index 0000000..868628f
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_12_corners.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_12_corners2.xml b/app/src/main/res/drawable/shape_white_12_corners2.xml
new file mode 100644
index 0000000..d1285c4
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_12_corners2.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_30_corners.xml b/app/src/main/res/drawable/shape_white_30_corners.xml
new file mode 100644
index 0000000..a6e1ed5
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_30_corners.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_dash_15_corners.xml b/app/src/main/res/drawable/shape_white_dash_15_corners.xml
new file mode 100644
index 0000000..3933de3
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_dash_15_corners.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_e6_12_corners.xml b/app/src/main/res/drawable/shape_white_e6_12_corners.xml
new file mode 100644
index 0000000..b0e23f4
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_e6_12_corners.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_f6_10_corners.xml b/app/src/main/res/drawable/shape_white_f6_10_corners.xml
new file mode 100644
index 0000000..6a5f42f
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_f6_10_corners.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_fb_15_corners.xml b/app/src/main/res/drawable/shape_white_fb_15_corners.xml
new file mode 100644
index 0000000..475fcc8
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_fb_15_corners.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_fb_15_corners2.xml b/app/src/main/res/drawable/shape_white_fb_15_corners2.xml
new file mode 100644
index 0000000..05e1a64
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_fb_15_corners2.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_base.xml b/app/src/main/res/layout/activity_base.xml
new file mode 100644
index 0000000..9da7115
--- /dev/null
+++ b/app/src/main/res/layout/activity_base.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_device_setting.xml b/app/src/main/res/layout/activity_device_setting.xml
new file mode 100644
index 0000000..90c2c03
--- /dev/null
+++ b/app/src/main/res/layout/activity_device_setting.xml
@@ -0,0 +1,216 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_food_search.xml b/app/src/main/res/layout/activity_food_search.xml
new file mode 100644
index 0000000..a2115b7
--- /dev/null
+++ b/app/src/main/res/layout/activity_food_search.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
new file mode 100644
index 0000000..0f82f14
--- /dev/null
+++ b/app/src/main/res/layout/activity_home.xml
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_prepare_cook.xml b/app/src/main/res/layout/activity_prepare_cook.xml
new file mode 100644
index 0000000..144f63d
--- /dev/null
+++ b/app/src/main/res/layout/activity_prepare_cook.xml
@@ -0,0 +1,287 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_sampling.xml b/app/src/main/res/layout/activity_sampling.xml
new file mode 100644
index 0000000..cac23c6
--- /dev/null
+++ b/app/src/main/res/layout/activity_sampling.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_select_dish.xml b/app/src/main/res/layout/activity_select_dish.xml
new file mode 100644
index 0000000..39a1a17
--- /dev/null
+++ b/app/src/main/res/layout/activity_select_dish.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_submit_dish.xml b/app/src/main/res/layout/activity_submit_dish.xml
new file mode 100644
index 0000000..6f37f38
--- /dev/null
+++ b/app/src/main/res/layout/activity_submit_dish.xml
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/custom_toast.xml b/app/src/main/res/layout/custom_toast.xml
new file mode 100644
index 0000000..2deaaa4
--- /dev/null
+++ b/app/src/main/res/layout/custom_toast.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_bottom_sheet.xml b/app/src/main/res/layout/dialog_bottom_sheet.xml
new file mode 100644
index 0000000..59f8bc2
--- /dev/null
+++ b/app/src/main/res/layout/dialog_bottom_sheet.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_bottom_sheet2.xml b/app/src/main/res/layout/dialog_bottom_sheet2.xml
new file mode 100644
index 0000000..98858e6
--- /dev/null
+++ b/app/src/main/res/layout/dialog_bottom_sheet2.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_common.xml b/app/src/main/res/layout/dialog_common.xml
new file mode 100644
index 0000000..d64c3b5
--- /dev/null
+++ b/app/src/main/res/layout/dialog_common.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_loading.xml b/app/src/main/res/layout/dialog_loading.xml
new file mode 100644
index 0000000..67410fa
--- /dev/null
+++ b/app/src/main/res/layout/dialog_loading.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_dish_list.xml b/app/src/main/res/layout/fragment_dish_list.xml
new file mode 100644
index 0000000..1e76c82
--- /dev/null
+++ b/app/src/main/res/layout/fragment_dish_list.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_dish_sampling.xml b/app/src/main/res/layout/fragment_dish_sampling.xml
new file mode 100644
index 0000000..390c42a
--- /dev/null
+++ b/app/src/main/res/layout/fragment_dish_sampling.xml
@@ -0,0 +1,281 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_sampling_list.xml b/app/src/main/res/layout/fragment_sampling_list.xml
new file mode 100644
index 0000000..3871be0
--- /dev/null
+++ b/app/src/main/res/layout/fragment_sampling_list.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_empty_view.xml b/app/src/main/res/layout/layout_empty_view.xml
new file mode 100644
index 0000000..2a5757d
--- /dev/null
+++ b/app/src/main/res/layout/layout_empty_view.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_food_remind.xml b/app/src/main/res/layout/layout_food_remind.xml
new file mode 100644
index 0000000..1f3369c
--- /dev/null
+++ b/app/src/main/res/layout/layout_food_remind.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_cell.xml b/app/src/main/res/layout/list_item_cell.xml
new file mode 100644
index 0000000..71c0e23
--- /dev/null
+++ b/app/src/main/res/layout/list_item_cell.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_dish.xml b/app/src/main/res/layout/list_item_dish.xml
new file mode 100644
index 0000000..c79b06b
--- /dev/null
+++ b/app/src/main/res/layout/list_item_dish.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_dish_cook.xml b/app/src/main/res/layout/list_item_dish_cook.xml
new file mode 100644
index 0000000..a9cca94
--- /dev/null
+++ b/app/src/main/res/layout/list_item_dish_cook.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_dish_record.xml b/app/src/main/res/layout/list_item_dish_record.xml
new file mode 100644
index 0000000..df63d85
--- /dev/null
+++ b/app/src/main/res/layout/list_item_dish_record.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_home_mode.xml b/app/src/main/res/layout/list_item_home_mode.xml
new file mode 100644
index 0000000..c59199f
--- /dev/null
+++ b/app/src/main/res/layout/list_item_home_mode.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_search_goods_info.xml b/app/src/main/res/layout/list_item_search_goods_info.xml
new file mode 100644
index 0000000..1da3490
--- /dev/null
+++ b/app/src/main/res/layout/list_item_search_goods_info.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..8fdd780
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..2762795
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,33 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
+ #F0F5FF
+ #FF000A2D
+ #FF646478
+ #FF141414
+ #FF8B8B8B
+ #FFABADAC
+ #FFABADAC
+ #FF646478
+ #B0BEC5
+ #30000000
+ #666666
+ #999999
+ #FBFBFB
+ #F6F6F6
+ #00BC71
+ #EBEBEB
+ #D6D6D6
+ #B4B4B4
+ #333333
+ #C8C8C8
+ #E6E6E6
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..ed82680
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,38 @@
+
+ 菜品配比终端
+ dish_match_terminal
+ 菜品配比终端
+ 选择菜品模式
+ 制作模式
+ 菜品快速制作,记录熟重
+ 采样模式
+ 菜品快速制作,记录熟重
+ 品控模式
+ 菜品快速制作,记录熟重
+ - 即将解锁 -
+ 早餐
+ 午餐
+ 晚餐
+ 菜品列表
+ 用量(克)
+ 在下方列表中选择食材计重
+ 菜品构成
+ 去制作
+ 当前食材与菜品构成不一致
+ 是否按当前食材制作或调整食材后再制作
+ 调料
+ 调料设置
+ 点击分格配置分配调料
+ 输入调料名称
+ 烹饪中
+ 已采样
+ 输入菜品名称或速记码
+ 输入菜品名称
+ 输入食材名称
+ 食材名称
+ 主辅材
+ 辅材
+ 主材
+ 新增采样
+ 添加食材
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..58d32ad
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..8250474
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,7 @@
+
+
+
+ vip.shuziweidao.com
+ 192.168.1.207
+
+
diff --git a/app/src/test/java/com/shuwei/dish/match/ExampleUnitTest.kt b/app/src/test/java/com/shuwei/dish/match/ExampleUnitTest.kt
new file mode 100644
index 0000000..8ea083f
--- /dev/null
+++ b/app/src/test/java/com/shuwei/dish/match/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.shuwei.dish.match
+
+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)
+ }
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..922f551
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,5 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.kotlin.android) apply false
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..20e2a01
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 0000000..df0c2e9
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,23 @@
+[versions]
+agp = "8.11.1"
+baserecyclerviewadapterhelper4 = "4.1.7"
+kotlin = "2.0.21"
+coreKtx = "1.10.1"
+junit = "4.13.2"
+junitVersion = "1.1.5"
+espressoCore = "3.5.1"
+appcompat = "1.6.1"
+material = "1.10.0"
+
+[libraries]
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..379cb0f
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Jul 17 15:32:57 CST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..c0c01d9
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,27 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ maven { url = uri("https://jitpack.io") }
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven { url = uri("https://maven.aliyun.com/repository/public") }
+ maven { url = uri("https://jitpack.io") }
+ }
+}
+
+rootProject.name = "DishMatch"
+include(":app")
+
\ No newline at end of file
diff --git a/system.keystore b/system.keystore
new file mode 100644
index 0000000..959c9b8
Binary files /dev/null and b/system.keystore differ