From 7373ccacbb8475a5c12a43e7f0423df5a95a0645 Mon Sep 17 00:00:00 2001
From: lvmeng <848755140@qq.com>
Date: Thu, 16 Apr 2026 18:05:46 +0800
Subject: [PATCH] =?UTF-8?q?feat(activity):=20=E6=96=B0=E5=A2=9E=E9=A3=9F?=
=?UTF-8?q?=E6=9D=90=E8=AF=86=E5=88=AB=E9=A1=B5=E9=9D=A2=EF=BC=8C=E9=87=8D?=
=?UTF-8?q?=E6=9E=84=E8=AF=86=E5=88=AB=E6=B5=81=E7=A8=8B=E5=B9=B6=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E5=A4=9A=E8=AE=BE=E5=A4=87=E5=B8=83=E5=B1=80=E9=80=82?=
=?UTF-8?q?=E9=85=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/src/main/AndroidManifest.xml | 5 +
.../dish/match/adapter/Scale18GridAdapter.kt | 4 +-
.../shuwei/dish/match/base/BaseActivity.kt | 5 +
.../shuwei/dish/match/dialog/CommonDialog.kt | 11 +-
.../shuwei/dish/match/dialog/LoadingDialog.kt | 8 +-
.../dish/match/ui/FoodRecognizeActivity.kt | 213 ++++++++++++++++++
.../dish/match/ui/PrepareCookActivity.kt | 50 ++--
.../com/shuwei/dish/match/ui/SlaveActivity.kt | 10 +-
.../res/drawable-xxxhdpi/ic_dish_clear.png | Bin 0 -> 5864 bytes
app/src/main/res/layout/activity_base.xml | 2 -
.../res/layout/activity_food_recognize.xml | 86 +++++++
app/src/main/res/layout/activity_slave.xml | 52 +++--
.../main/res/layout/list_item_dish_cook.xml | 15 +-
13 files changed, 413 insertions(+), 48 deletions(-)
create mode 100644 app/src/main/java/com/shuwei/dish/match/ui/FoodRecognizeActivity.kt
create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_dish_clear.png
create mode 100644 app/src/main/res/layout/activity_food_recognize.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3b24cb5..095ded5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -111,6 +111,11 @@
android:theme="@style/Theme.DishMatch.NoSplash"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
+
(mu
b.root.layoutParams = (b.root.layoutParams as ViewGroup.MarginLayoutParams).also {
it.width = cellSize
it.height = cellSize
- it.setMargins(margin, margin, margin, margin)
+ // 第1行:顶部间距为0,底部间距2dp,左右保持原有 margin
+ if (viewType == 0) it.setMargins(margin, 0, margin, 2.dp)
+ else it.setMargins(margin, margin, margin, margin)
}
val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt()
b.tvAddr.textSize = (baseSp * 0.16f).coerceIn(9f, 14f)
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
index fbc5be1..741a0f1 100644
--- a/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt
+++ b/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt
@@ -26,6 +26,7 @@ import com.shuwei.dish.match.entity.SeasoningEntity
import com.shuwei.dish.match.net.NetViewModel
import com.shuwei.dish.match.ui.InitActivity
import com.shuwei.dish.match.utils.ActivityManager
+import com.shuwei.dish.match.utils.ext.dp
import com.shuwei.dish.match.utils.ext.gone
import com.shuwei.dish.match.utils.ext.invisible
import com.shuwei.dish.match.utils.ext.visible
@@ -65,6 +66,10 @@ open class BaseActivity : AppCompatActivity() {
// systemBarsBehavior =
// WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE // 滑动时临时显示
// }
+ // 主设备垂直 padding 30dp,子设备 15dp
+ val verticalPadding = if (GlobalData.deviceRole == DeviceRole.MASTER) 30.dp else 10.dp
+ binding.tvLeftTime.setPadding(0, verticalPadding, 0, verticalPadding)
+ binding.tvRightTime.setPadding(0, verticalPadding, 0, verticalPadding)
binding.llTitleBar.gone()
binding.ivBack.setOnClickListener { finish() }
}
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
index 5776e83..365115f 100644
--- a/app/src/main/java/com/shuwei/dish/match/dialog/CommonDialog.kt
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/CommonDialog.kt
@@ -7,7 +7,11 @@ import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.View
import android.view.Window
+import android.widget.LinearLayout
import androidx.annotation.StyleRes
+import androidx.core.view.updateLayoutParams
+import com.shuwei.dish.match.base.DeviceRole
+import com.shuwei.dish.match.base.GlobalData
import com.shuwei.dish.match.databinding.DialogCommonBinding
import com.shuwei.dish.match.utils.ext.dp
import java.lang.ref.WeakReference
@@ -55,12 +59,17 @@ open class CommonDialog(
binding = DialogCommonBinding.inflate(layoutInflater)
setContentView(binding.root)
window?.run {
+ val screenWidth = context.resources.displayMetrics.widthPixels
+ val isMaster = GlobalData.deviceRole == DeviceRole.MASTER
attributes = attributes.apply {
- width = 660.dp
+ width = if (isMaster) (screenWidth * 0.72f).toInt() else (screenWidth * 0.60f).toInt()
}
setBackgroundDrawable(ColorDrawable())
setCancelable(false)
}
+ val verticalMargin = if (GlobalData.deviceRole == DeviceRole.MASTER) 35.dp else 20.dp
+ binding.tvTitle.updateLayoutParams { topMargin = verticalMargin }
+ binding.tvContent.updateLayoutParams { bottomMargin = verticalMargin }
binding.btnLeft.setOnClickListener {
negativeClick?.invoke()
dismiss()
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
index d004dcb..f893ce8 100644
--- a/app/src/main/java/com/shuwei/dish/match/dialog/LoadingDialog.kt
+++ b/app/src/main/java/com/shuwei/dish/match/dialog/LoadingDialog.kt
@@ -66,10 +66,10 @@ class LoadingDialog(
setCancelable(true)
window?.run {
setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
- setFlags(
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- );
+// setFlags(
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+// );
}
setOnDismissListener {
onDismiss()
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/FoodRecognizeActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/FoodRecognizeActivity.kt
new file mode 100644
index 0000000..fc0df2b
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/FoodRecognizeActivity.kt
@@ -0,0 +1,213 @@
+package com.shuwei.dish.match.ui
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import androidx.recyclerview.widget.GridLayoutManager
+import com.shuwei.dish.match.adapter.GoodsInfoSearchAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.databinding.ActivityFoodRecognizeBinding
+import com.shuwei.dish.match.dialog.FoodSearchDialog
+import com.shuwei.dish.match.entity.CookFoodGoodsEntity
+import com.shuwei.dish.match.utils.ActivityManager
+import com.shuwei.dish.match.utils.AddressUtil
+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.visible
+
+/**
+ * 食材识别结果页面
+ * 展示识别到的食材照片、食材列表、选中食材名称及秤1重量
+ */
+class FoodRecognizeActivity : BaseActivity() {
+
+ companion object {
+ private const val TAG = "FoodRecognizeActivity"
+ private const val EXTRA_IMAGE_URI = "extra_image_uri"
+ const val EXTRA_SELECTED_ITEM = "extra_selected_item"
+
+ /** 内存缓存食材列表,避免通过 Intent 序列化传递大数据 */
+ private var pendingGoodsList: ArrayList? = null
+
+ /**
+ * 启动本页面,通过 onResult 回调返回用户选中的食材
+ * @param activity 宿主 Activity
+ * @param imageUri 食材照片路径(可为空)
+ * @param goodsList 识别到的食材列表
+ * @param onResult 页面关闭后回调,携带用户选中的食材(未选中时为 null)
+ */
+ fun start(
+ activity: BaseActivity,
+ imageUri: String? = null,
+ goodsList: ArrayList = arrayListOf(),
+ onResult: (CookFoodGoodsEntity?) -> Unit = {}
+ ) {
+ pendingGoodsList = goodsList
+ val intent = Intent(activity, FoodRecognizeActivity::class.java).apply {
+ putExtra(EXTRA_IMAGE_URI, imageUri)
+ }
+ activity.startActivity(intent) { resultIntent ->
+ @Suppress("DEPRECATION")
+ val item = resultIntent?.getSerializableExtra(EXTRA_SELECTED_ITEM) as? CookFoodGoodsEntity
+ onResult(item)
+ }
+ }
+
+ /**
+ * 关闭当前识别页面,并将选中食材通过 Activity Result 回传
+ * 由外部(如重量归零时)调用
+ */
+ fun close() {
+ ActivityManager.getActivityStack()
+ .filterIsInstance()
+ .lastOrNull()
+ ?.finishWithResult()
+ }
+ }
+
+ private lateinit var binding: ActivityFoodRecognizeBinding
+
+ private val list = mutableListOf()
+
+ private val adapter = GoodsInfoSearchAdapter(list).apply {
+ setOnItemClickListener { _, _, position ->
+ // 更新选中状态
+ list.forEachIndexed { i, item -> item.isClicked = (i == position) }
+ notifyDataSetChanged()
+ // 同步更新选中食材名称
+ binding.tvSelectedFood.text = list[position].goodsName ?: "-"
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityFoodRecognizeBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setHeaderBackground()
+
+ // 显示标题栏
+ setTitleBar(titleBarAction = { it.visible() }, titleAction = { it.text = "食材识别" })
+
+ initData()
+ initRecyclerView()
+ initClickListeners()
+ registerWeightListener()
+ }
+
+ /**
+ * 从 Intent 读取数据并初始化页面
+ */
+ private fun initData() {
+ // 加载食材照片
+ val imageUri = intent.getStringExtra(EXTRA_IMAGE_URI)
+ if (!imageUri.isNullOrBlank()) {
+ binding.ivFoodPhoto.setImageURI(Uri.parse(imageUri))
+ }
+
+ // 取出内存缓存的食材列表,取用后立即清空
+ val goodsList = pendingGoodsList?.also { pendingGoodsList = null }
+ if (!goodsList.isNullOrEmpty()) {
+ list.addAll(goodsList)
+ // 默认选中第一项
+ list[0].isClicked = true
+ binding.tvSelectedFood.text = list[0].goodsName ?: "-"
+ }
+ }
+
+ /**
+ * 初始化 RecyclerView
+ */
+ private fun initRecyclerView() {
+ binding.recyclerView.run {
+ layoutManager = GridLayoutManager(this@FoodRecognizeActivity, 2)
+ adapter = this@FoodRecognizeActivity.adapter
+ }
+ updateListVisibility()
+ }
+
+ /**
+ * 根据列表是否有数据控制 RecyclerView 显隐
+ */
+ private fun updateListVisibility() {
+ if (list.isEmpty()) {
+ binding.recyclerView.gone()
+ } else {
+ binding.recyclerView.visible()
+ }
+ }
+
+ /**
+ * 初始化按钮点击事件
+ */
+ private fun initClickListeners() {
+ // 更换食材:打开食材搜索弹窗
+ binding.btnChangeFood.clickWithDebounce {
+ val currentName = if (list.isNotEmpty()) list.firstOrNull { it.isClicked }?.goodsName else null
+ FoodSearchDialog(
+ activity = this,
+ defGoodsName = currentName,
+ onItemSelected = { item ->
+ // 用搜索结果替换当前选中食材
+ updateSelectedFood(item)
+ }
+ ).show()
+ }
+
+ // 取消:关闭页面
+ binding.btnCancel.setOnClickListener { finish() }
+ }
+
+ /**
+ * 用新食材替换当前选中项(或追加到列表首位)
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ private fun updateSelectedFood(item: CookFoodGoodsEntity) {
+ item.isClicked = true
+ val clickedIndex = list.indexOfFirst { it.isClicked && it.goodsId != item.goodsId }
+ if (clickedIndex >= 0) {
+ list[clickedIndex].isClicked = false
+ }
+ // 若列表中已存在则直接选中,否则插入到首位
+ val existIndex = list.indexOfFirst { it.goodsId == item.goodsId }
+ if (existIndex >= 0) {
+ list.forEachIndexed { i, e -> e.isClicked = (i == existIndex) }
+ } else {
+ list.add(0, item)
+ }
+ adapter.notifyDataSetChanged()
+ binding.tvSelectedFood.text = item.goodsName ?: "-"
+ updateListVisibility()
+ }
+
+ /**
+ * 注册秤1重量监听
+ */
+ private fun registerWeightListener() {
+ WeightUtil.addWeightListener(TAG) { address, _, weight ->
+ if (address == AddressUtil.ONE) {
+ runOnUiThread {
+ binding.tvWeight.text = "$weight g"
+ }
+ }
+ }
+ }
+
+ /**
+ * 携带当前选中食材关闭页面
+ */
+ private fun finishWithResult() {
+ val selected = list.firstOrNull { it.isClicked }
+ val intent = Intent().apply {
+ selected?.let { putExtra(EXTRA_SELECTED_ITEM, it) }
+ }
+ setResult(RESULT_OK, intent)
+ finish()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ WeightUtil.removeWeightListener(TAG)
+ }
+}
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
index b63eda9..d3f9b54 100644
--- a/app/src/main/java/com/shuwei/dish/match/ui/PrepareCookActivity.kt
+++ b/app/src/main/java/com/shuwei/dish/match/ui/PrepareCookActivity.kt
@@ -12,7 +12,6 @@ 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.dialog.CommonDialog
-import com.shuwei.dish.match.dialog.FoodRecognizeDialog
import com.shuwei.dish.match.dialog.FoodSearchDialog
import com.shuwei.dish.match.entity.CookFoodEntity
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
@@ -158,6 +157,10 @@ class PrepareCookActivity : BaseActivity() {
}
private val isTakingPhoto = AtomicBoolean(false)
+ private var isRecognizeOpen = false
+ // 页面可见时允许识别,onPause 后禁止,onResume 后恢复
+ private var isRecognizeEnabled = true
+ private var lastPhotoUri: Uri? = null
private var lastWeight = 0.0
private var currentWeight = 0.0
@@ -168,10 +171,11 @@ class PrepareCookActivity : BaseActivity() {
private fun recognizeFood(weight: Double) {
this.currentWeight = weight
if (weight < WEIGHT_RECOGNIZE_VALUE) {
- if (recognizeDialog.isShowing) recognizeDialog.dismiss()
+ isRecognizeOpen = false
+ FoodRecognizeActivity.close()
return
}
- if (isTakingPhoto.get() || recognizeDialog.isShowing || abs(lastWeight - weight) <= WEIGHT_CHANGE_VALUE) return
+ if (!isRecognizeEnabled || isTakingPhoto.get() || isRecognizeOpen || abs(lastWeight - weight) <= WEIGHT_CHANGE_VALUE) return
isTakingPhoto.set(true)
cameraUtils.takePhoto(
succCallback = cameraSuccessCallback,
@@ -194,9 +198,13 @@ class PrepareCookActivity : BaseActivity() {
// materialType =
isNewDishType = true
isOriginalData = false
+ useWeight = lastWeight
+ isSetFinished = true
})
- onFoodItemClick(list.size - 1)
- binding.rvDishPartList.smoothScrollToPosition(list.size - 1)
+ val positon = list.size - 1
+ dishPartAdapter.notifyItemInserted(positon)
+ onFoodItemClick(positon)
+ binding.rvDishPartList.smoothScrollToPosition(positon)
}
/**
@@ -298,18 +306,24 @@ class PrepareCookActivity : BaseActivity() {
private var firstReqSize = 0
private val list = mutableListOf()
- private val recognizeDialog by lazy {
- FoodRecognizeDialog(
- activity = this,
- onDismiss = { isTakingPhoto.set(false) },
- onItemSelected = foodSelectCallback
- )
- }
private val dishPartAdapter by lazy {
DishPartAdapter(list).apply {
setOnItemClickListener { _, _, positon ->
onFoodItemClick(positon)
}
+ addOnItemChildClickListener(R.id.ivClearIcon) { _, _, positon ->
+ if (list[positon].isOriginalData) {
+ list[positon].run {
+ isNewDishType = false
+ isOriginalData = false
+ useWeight = 0.0
+ isSetFinished = false
+ }
+ notifyItemChanged(positon)
+ return@addOnItemChildClickListener
+ }
+ removeAt(positon)
+ }
}
}
@@ -388,11 +402,14 @@ class PrepareCookActivity : BaseActivity() {
override fun onResume() {
super.onResume()
+ isRecognizeEnabled = true
+ isRecognizeOpen = false
cameraUtils.bind()
}
override fun onPause() {
super.onPause()
+ isRecognizeEnabled = false
cameraUtils.unbind()
}
@@ -438,6 +455,7 @@ class PrepareCookActivity : BaseActivity() {
*/
private val cameraSuccessCallback: (Uri) -> Unit = { uri ->
Log.d(TAG, "takePhoto success")
+ lastPhotoUri = uri
lifecycleScope.launch {
withContext(Dispatchers.IO) {
val bitmap = ImageUtil.uriToBitmap(this@PrepareCookActivity, uri)
@@ -485,7 +503,13 @@ class PrepareCookActivity : BaseActivity() {
foodId = index.toString()
))
}
- recognizeDialog.loadData(foodList)
+ FoodRecognizeActivity.start(
+ activity = this,
+ imageUri = lastPhotoUri?.toString(),
+ goodsList = ArrayList(foodList),
+ onResult = { item -> item?.let { foodSelectCallback(it) } }
+ )
+ isRecognizeOpen = true
isTakingPhoto.set(false)
lastWeight = currentWeight
}
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SlaveActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SlaveActivity.kt
index 175384c..8496e4b 100644
--- a/app/src/main/java/com/shuwei/dish/match/ui/SlaveActivity.kt
+++ b/app/src/main/java/com/shuwei/dish/match/ui/SlaveActivity.kt
@@ -2,8 +2,10 @@ package com.shuwei.dish.match.ui
import android.annotation.SuppressLint
import android.os.Bundle
+import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
+import android.widget.LinearLayout
import androidx.activity.addCallback
import com.google.android.flexbox.AlignItems
import com.google.android.flexbox.FlexDirection
@@ -74,7 +76,11 @@ class SlaveActivity : BaseActivity() {
val smallSize = usable / 9
val largeSize = (usable - smallSize * 6) / 2
val rvHeight = smallSize * 3 + 3 * 4.dp
- binding.rvScaleList.layoutParams = binding.rvScaleList.layoutParams.also { it.height = rvHeight }
+ binding.rvScaleList.updateLayoutParams {
+ height = rvHeight
+ weight = 0f
+ topMargin = 20.dp
+ }
binding.rvScaleList.layoutManager = FlexboxLayoutManager(this).apply {
flexDirection = FlexDirection.COLUMN
flexWrap = FlexWrap.WRAP
@@ -86,6 +92,7 @@ class SlaveActivity : BaseActivity() {
binding.rvScaleList.adapter = scale22Adapter
}
ScaleDeviceConfig.DEVICE_ID_18 -> {
+ binding.rvScaleList.updateLayoutParams { topMargin = 0 }
binding.rvScaleList.layoutManager = GridLayoutManager(this, 6).apply {
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int) = 1
@@ -97,6 +104,7 @@ class SlaveActivity : BaseActivity() {
binding.rvScaleList.adapter = scale18Adapter
}
else -> {
+ binding.rvScaleList.updateLayoutParams { topMargin = 20.dp }
binding.rvScaleList.layoutManager = LinearLayoutManager(this)
linearAdapter.setOnItemClickListener { _, _, position ->
val item = linearAdapter.items.getOrNull(position) ?: return@setOnItemClickListener
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_dish_clear.png b/app/src/main/res/drawable-xxxhdpi/ic_dish_clear.png
new file mode 100644
index 0000000000000000000000000000000000000000..970c57a01cfe52a88dd03485acd314393e74e475
GIT binary patch
literal 5864
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_slave.xml b/app/src/main/res/layout/activity_slave.xml
index 3fe55c9..47b0e2a 100644
--- a/app/src/main/res/layout/activity_slave.xml
+++ b/app/src/main/res/layout/activity_slave.xml
@@ -4,20 +4,36 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:padding="12dp"
+ android:paddingHorizontal="5dp"
tools:background="@color/bg_color">
-
-
+
+ android:orientation="horizontal"
+ android:gravity="center">
+
+
+
+
+
+
+
+
-
-
-
+
+