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"> + + + + + + + + - - - + +