Compare commits
5
Commits
87bf11454c
...
82217b4fb1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82217b4fb1 | ||
|
|
72ecc8fcd6 | ||
|
|
99d670390a | ||
|
|
d3b69c4e46 | ||
|
|
193acff1e0 |
@@ -9,7 +9,9 @@ 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
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class DishPartAdapter(list: MutableList<CookFoodGoodsEntity>) :
|
||||
@@ -36,12 +38,16 @@ class DishPartAdapter(list: MutableList<CookFoodGoodsEntity>) :
|
||||
if (item.isSamplingPage) R.color.black999 else R.color.dish_green
|
||||
)
|
||||
)
|
||||
|
||||
ivOperateIcon.run {
|
||||
if (item.isSamplingPage) gone() else visible()
|
||||
}
|
||||
ivClearIcon.visible()
|
||||
ivClearIcon.setImageResource(
|
||||
if (item.isOriginalData) R.drawable.ic_dish_clear
|
||||
else R.drawable.ic_delete
|
||||
)
|
||||
ivOperateIcon.setImageResource(
|
||||
if (item.isSamplingPage)
|
||||
//采集页面
|
||||
R.drawable.ic_delete
|
||||
else
|
||||
//制作页面
|
||||
if (item.isSetFinished) R.drawable.ic_dish_selected
|
||||
else R.drawable.ic_dish_unselected
|
||||
)
|
||||
@@ -53,5 +59,4 @@ class DishPartAdapter(list: MutableList<CookFoodGoodsEntity>) :
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,9 @@ 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
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
|
||||
class GoodsInfoSearchAdapter(private var list: MutableList<CookFoodGoodsEntity>) :
|
||||
BaseQuickAdapter<CookFoodGoodsEntity, GoodsInfoSearchAdapter.VH>(list) {
|
||||
@@ -18,20 +21,29 @@ class GoodsInfoSearchAdapter(private var list: MutableList<CookFoodGoodsEntity>)
|
||||
position: Int,
|
||||
item: CookFoodGoodsEntity?
|
||||
) {
|
||||
item ?: return
|
||||
holder.binding.tvGoodsInfo.run {
|
||||
text = item?.goodsName
|
||||
text = item.goodsName
|
||||
setBackgroundResource(
|
||||
if (item?.isClicked == true) R.drawable.shape_green_stroke
|
||||
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
|
||||
if (item.isClicked == true) R.color.dish_green
|
||||
else R.color.black666
|
||||
)
|
||||
)
|
||||
}
|
||||
if (item.foodScore == -1){
|
||||
holder.binding.tvFoodScore.gone()
|
||||
} else {
|
||||
holder.binding.tvFoodScore.let {
|
||||
it.visible()
|
||||
it.text = "${(item.foodScore / 100.0).roundedDecimalPlace(2)}%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.shuwei.dish.match.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.ListItemScale22RowBinding
|
||||
import com.shuwei.dish.match.scale.ScaleData
|
||||
import com.shuwei.dish.match.scale.ScaleDeviceConfig
|
||||
@@ -25,6 +27,9 @@ class Scale18GridAdapter : BaseQuickAdapter<ScaleData, Scale18GridAdapter.VH>(mu
|
||||
/** 用 address=0 的哨兵表示空位 */
|
||||
private val empty = ScaleData("", 0, 0.0, -1, 0)
|
||||
|
||||
/** 当前高亮的格子位置,-1 表示无高亮 */
|
||||
private var highlightedPosition: Int = -1
|
||||
|
||||
/** 点击回调,在 onCreateViewHolder 中绑定,不受 notifyItemChanged 影响 */
|
||||
var onItemClick: ((ScaleData) -> Unit)? = null
|
||||
|
||||
@@ -91,6 +96,38 @@ class Scale18GridAdapter : BaseQuickAdapter<ScaleData, Scale18GridAdapter.VH>(mu
|
||||
holder.b.tvAddr.text = if (valid) "秤${item!!.address}" else ""
|
||||
holder.b.tvWeight.text = if (valid) "${item!!.weight}g" else ""
|
||||
holder.b.tvState.text = if (valid) stateStr(item!!.state) else ""
|
||||
// 高亮格子:红底白字;其余恢复默认
|
||||
if (position == highlightedPosition) {
|
||||
holder.b.root.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444))
|
||||
val white = ContextCompat.getColor(holder.b.root.context, R.color.white)
|
||||
holder.b.tvAddr.setTextColor(white)
|
||||
holder.b.tvWeight.setTextColor(white)
|
||||
holder.b.tvState.setTextColor(white)
|
||||
} else {
|
||||
holder.b.root.setBackgroundResource(R.drawable.shape_scale_cell)
|
||||
val normal = ContextCompat.getColor(holder.b.root.context, R.color.home_title)
|
||||
holder.b.tvAddr.setTextColor(normal)
|
||||
holder.b.tvWeight.setTextColor(normal)
|
||||
holder.b.tvState.setTextColor(normal)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 高亮指定位置的格子(红底白字),同时清除上一个高亮
|
||||
* @param position 要高亮的格子索引
|
||||
*/
|
||||
fun highlightPosition(position: Int) {
|
||||
val prev = highlightedPosition
|
||||
highlightedPosition = position
|
||||
if (prev >= 0) notifyItemChanged(prev)
|
||||
if (position >= 0) notifyItemChanged(position)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有高亮,恢复默认样式
|
||||
*/
|
||||
fun clearHighlight() {
|
||||
highlightPosition(-1)
|
||||
}
|
||||
|
||||
private fun stateStr(state: Int) = when (state) {
|
||||
|
||||
@@ -4,10 +4,12 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.google.android.flexbox.FlexboxLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.databinding.ListItemScale22RowBinding
|
||||
import com.shuwei.dish.match.scale.ScaleData
|
||||
import com.shuwei.dish.match.scale.ScaleDeviceConfig
|
||||
@@ -32,6 +34,9 @@ class Scale22GridAdapter(
|
||||
/** 用 address=0 的哨兵表示空位 */
|
||||
private val empty = ScaleData("", 0, 0.0, -1, 0)
|
||||
|
||||
/** 当前高亮的格子位置,-1 表示无高亮 */
|
||||
private var highlightedPosition: Int = -1
|
||||
|
||||
/** 点击回调,在 onCreateViewHolder 中绑定,不受 notifyItemChanged 影响 */
|
||||
var onItemClick: ((ScaleData) -> Unit)? = null
|
||||
|
||||
@@ -93,6 +98,38 @@ class Scale22GridAdapter(
|
||||
holder.b.tvAddr.text = if (valid) "秤${item!!.address}" else ""
|
||||
holder.b.tvWeight.text = if (valid) "${item!!.weight}g" else ""
|
||||
holder.b.tvState.text = if (valid) stateStr(item!!.state) else ""
|
||||
// 高亮格子:红底白字;其余恢复默认
|
||||
if (position == highlightedPosition) {
|
||||
holder.b.root.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444))
|
||||
val white = ContextCompat.getColor(holder.b.root.context, R.color.white)
|
||||
holder.b.tvAddr.setTextColor(white)
|
||||
holder.b.tvWeight.setTextColor(white)
|
||||
holder.b.tvState.setTextColor(white)
|
||||
} else {
|
||||
holder.b.root.setBackgroundResource(R.drawable.shape_scale_cell)
|
||||
val normal = ContextCompat.getColor(holder.b.root.context, R.color.home_title)
|
||||
holder.b.tvAddr.setTextColor(normal)
|
||||
holder.b.tvWeight.setTextColor(normal)
|
||||
holder.b.tvState.setTextColor(normal)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 高亮指定位置的格子(红底白字),同时清除上一个高亮
|
||||
* @param position 要高亮的格子索引
|
||||
*/
|
||||
fun highlightPosition(position: Int) {
|
||||
val prev = highlightedPosition
|
||||
highlightedPosition = position
|
||||
if (prev >= 0) notifyItemChanged(prev)
|
||||
if (position >= 0) notifyItemChanged(position)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有高亮,恢复默认样式
|
||||
*/
|
||||
fun clearHighlight() {
|
||||
highlightPosition(-1)
|
||||
}
|
||||
|
||||
private fun stateStr(state: Int) = when (state) {
|
||||
|
||||
@@ -86,4 +86,7 @@ class CookFoodGoodsEntity(
|
||||
//true-原始数据,false-非原始数据
|
||||
@Ignore
|
||||
var isOriginalData: Boolean = true
|
||||
|
||||
@Ignore
|
||||
var foodScore: Int = -1
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.util.Log
|
||||
import com.shuwei.dish.match.base.DeviceRole
|
||||
import com.shuwei.dish.match.base.GlobalData
|
||||
import com.shuwei.dish.match.utils.NetworkUtil
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
@@ -165,7 +166,7 @@ object ScaleServiceManager {
|
||||
*/
|
||||
fun sendTare(deviceId: String, address: Int): Boolean {
|
||||
return if (deviceId == GlobalData.deviceId) {
|
||||
com.shuwei.dish.match.utils.WeightUtil.tareTwo(address)
|
||||
WeightUtil.tareTwo(address)
|
||||
true
|
||||
} else {
|
||||
val cmd = ScaleCommand(ScaleCommand.CMD_TARE, deviceId, address)
|
||||
|
||||
@@ -137,15 +137,18 @@ class ScaleWebSocketServer(private val deviceId: String, private val context: Co
|
||||
try {
|
||||
val cmd = gson.fromJson(message, ScaleCommand::class.java)
|
||||
// 校验指令目标设备是否为本机
|
||||
if (cmd.deviceId != deviceId) return
|
||||
if (cmd.deviceId != deviceId) {
|
||||
Log.d(TAG, "收到清零指令, 但设备号不正确, deviceId=${cmd.deviceId}")
|
||||
return
|
||||
}
|
||||
when (cmd.cmd) {
|
||||
ScaleCommand.CMD_TARE -> {
|
||||
Log.d(TAG, "收到清零指令, address=${cmd.address}")
|
||||
com.shuwei.dish.match.utils.WeightUtil.tareTwo(cmd.address)
|
||||
WeightUtil.tareTwo(cmd.address)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "解析指令失败: ${e.message}")
|
||||
Log.w(TAG, "收到清零指令, 解析指令失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ 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
|
||||
import androidx.core.net.toUri
|
||||
|
||||
/**
|
||||
* 食材识别结果页面
|
||||
@@ -71,12 +72,25 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
|
||||
private val list = mutableListOf<CookFoodGoodsEntity>()
|
||||
|
||||
/** 当前选中的列表位置,-1 表示无选中 */
|
||||
private var selectedPosition = -1
|
||||
|
||||
/** 秤1当前实时重量 */
|
||||
private var currentWeight = 0.0
|
||||
|
||||
/** 重量减少时延迟更新的任务,页面关闭前取消可防止用错误重量 */
|
||||
private var pendingWeightRunnable: Runnable? = null
|
||||
|
||||
/** 当前待延迟更新的目标重量,避免相同重量重复重置计时器 */
|
||||
private var pendingWeight = 0.0
|
||||
|
||||
private val adapter = GoodsInfoSearchAdapter(list).apply {
|
||||
setOnItemClickListener { _, _, position ->
|
||||
// 更新选中状态
|
||||
list.forEachIndexed { i, item -> item.isClicked = (i == position) }
|
||||
// 点击选择时记录当前秤重量
|
||||
list[position].useWeight = currentWeight
|
||||
notifyDataSetChanged()
|
||||
// 同步更新选中食材名称
|
||||
selectedPosition = position
|
||||
binding.tvSelectedFood.text = list[position].goodsName ?: "-"
|
||||
}
|
||||
}
|
||||
@@ -85,6 +99,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityFoodRecognizeBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
registerWeightListener()
|
||||
setHeaderBackground()
|
||||
|
||||
// 显示标题栏
|
||||
@@ -93,7 +108,6 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
initData()
|
||||
initRecyclerView()
|
||||
initClickListeners()
|
||||
registerWeightListener()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +117,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
// 加载食材照片
|
||||
val imageUri = intent.getStringExtra(EXTRA_IMAGE_URI)
|
||||
if (!imageUri.isNullOrBlank()) {
|
||||
binding.ivFoodPhoto.setImageURI(Uri.parse(imageUri))
|
||||
binding.ivFoodPhoto.setImageURI(imageUri.toUri())
|
||||
}
|
||||
|
||||
// 取出内存缓存的食材列表,取用后立即清空
|
||||
@@ -111,6 +125,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
if (!goodsList.isNullOrEmpty()) {
|
||||
list.addAll(goodsList)
|
||||
// 默认选中第一项
|
||||
selectedPosition = 0
|
||||
list[0].isClicked = true
|
||||
binding.tvSelectedFood.text = list[0].goodsName ?: "-"
|
||||
}
|
||||
@@ -144,14 +159,11 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
private fun initClickListeners() {
|
||||
// 更换食材:打开食材搜索弹窗
|
||||
binding.btnChangeFood.clickWithDebounce {
|
||||
val currentName = if (list.isNotEmpty()) list.firstOrNull { it.isClicked }?.goodsName else null
|
||||
val currentName = list.getOrNull(selectedPosition)?.goodsName
|
||||
FoodSearchDialog(
|
||||
activity = this,
|
||||
defGoodsName = currentName,
|
||||
onItemSelected = { item ->
|
||||
// 用搜索结果替换当前选中食材
|
||||
updateSelectedFood(item)
|
||||
}
|
||||
onItemSelected = { item -> updateSelectedFood(item) }
|
||||
).show()
|
||||
}
|
||||
|
||||
@@ -164,17 +176,14 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
*/
|
||||
@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) }
|
||||
selectedPosition = existIndex
|
||||
} else {
|
||||
list.add(0, item)
|
||||
list.forEachIndexed { i, e -> e.isClicked = (i == 0) }
|
||||
selectedPosition = 0
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
binding.tvSelectedFood.text = item.goodsName ?: "-"
|
||||
@@ -183,22 +192,55 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
|
||||
/**
|
||||
* 注册秤1重量监听
|
||||
* 只有重量高于识别阈值时才更新选中食材的 useWeight,
|
||||
* 低于阈值说明食材已被取走,保留上次有效值等待页面关闭
|
||||
*/
|
||||
private fun registerWeightListener() {
|
||||
WeightUtil.addWeightListener(TAG) { address, _, weight ->
|
||||
if (address == AddressUtil.ONE) {
|
||||
WeightUtil.addWeightListener(TAG) { address, state, weight ->
|
||||
if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) {
|
||||
runOnUiThread {
|
||||
binding.tvWeight.text = "$weight g"
|
||||
currentWeight = weight
|
||||
binding.tvWeight.run {
|
||||
if (tag != weight) {
|
||||
text = "$weight g"
|
||||
tag = weight
|
||||
}
|
||||
}
|
||||
if (weight >= PrepareCookActivity.WEIGHT_RECOGNIZE_VALUE) {
|
||||
adapter.items.firstOrNull { it.isClicked }?.let { item ->
|
||||
if (weight > (item.useWeight ?: 0.0)) {
|
||||
// 重量增加:立即更新
|
||||
cancelPendingWeightUpdate()
|
||||
item.useWeight = currentWeight
|
||||
} else if (pendingWeight != weight) {
|
||||
// 重量减少且目标值变化:重置延迟任务,3 秒无新变化后更新
|
||||
cancelPendingWeightUpdate()
|
||||
pendingWeight = weight
|
||||
pendingWeightRunnable = Runnable {
|
||||
item.useWeight = weight
|
||||
pendingWeightRunnable = null
|
||||
}.also { handler.postDelayed(it, 3000) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消待执行的延迟重量更新任务
|
||||
*/
|
||||
private fun cancelPendingWeightUpdate() {
|
||||
pendingWeightRunnable?.let { handler.removeCallbacks(it) }
|
||||
pendingWeightRunnable = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 携带当前选中食材关闭页面
|
||||
*/
|
||||
private fun finishWithResult() {
|
||||
val selected = list.firstOrNull { it.isClicked }
|
||||
val selected = list.getOrNull(selectedPosition)
|
||||
val intent = Intent().apply {
|
||||
selected?.let { putExtra(EXTRA_SELECTED_ITEM, it) }
|
||||
}
|
||||
@@ -208,6 +250,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
WeightUtil.removeWeightListener(TAG)
|
||||
cancelPendingWeightUpdate()
|
||||
// WeightUtil.removeWeightListener(TAG)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,8 +158,8 @@ class HomeActivity : BaseActivity() {
|
||||
return@countCookFood
|
||||
}
|
||||
//无烹饪数据打开新增采样页面
|
||||
startActivity<DishSamplingActivity> {
|
||||
putExtra(DishSamplingActivity.PAGE_FROM, DishSamplingActivity.HOME)
|
||||
startActivity<PrepareCookActivity> {
|
||||
putExtra(PrepareCookActivity.PAGE_FROM, PrepareCookActivity.HOME)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -113,8 +113,8 @@ class InitActivity : BaseActivity() {
|
||||
return@countCookFood
|
||||
}
|
||||
//无烹饪数据打开新增采样页面
|
||||
startActivity<DishSamplingActivity> {
|
||||
putExtra(DishSamplingActivity.PAGE_FROM, DishSamplingActivity.HOME)
|
||||
startActivity<PrepareCookActivity> {
|
||||
putExtra(PrepareCookActivity.PAGE_FROM, PrepareCookActivity.HOME)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,35 @@
|
||||
package com.shuwei.dish.match.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Typeface
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.addCallback
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
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.LayoutCameraPreviewBinding
|
||||
import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.dialog.FoodSearchDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.addCallback
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.shuwei.dish.match.databinding.LayoutCameraPreviewBinding
|
||||
import com.shuwei.dish.match.objbox.FoodModule
|
||||
import com.shuwei.dish.match.utils.AddressUtil
|
||||
import com.shuwei.dish.match.utils.CameraUtils
|
||||
import com.shuwei.dish.match.utils.ImageUtil
|
||||
import com.shuwei.dish.match.utils.KeyboardUtil
|
||||
import com.shuwei.dish.match.utils.SpTool
|
||||
import com.shuwei.dish.match.utils.SwipeCallback
|
||||
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.gone
|
||||
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
|
||||
@@ -46,6 +50,9 @@ class PrepareCookActivity : BaseActivity() {
|
||||
companion object {
|
||||
const val TAG = "CookActivity"
|
||||
const val FOOD_ITEM = "foodItem"
|
||||
const val FOOD_NAME = "foodName"
|
||||
const val PAGE_FROM = "pageFrom"
|
||||
const val HOME = "home"
|
||||
const val WEIGHT_CHANGE_VALUE = 5
|
||||
const val WEIGHT_RECOGNIZE_VALUE = 10
|
||||
}
|
||||
@@ -56,6 +63,12 @@ class PrepareCookActivity : BaseActivity() {
|
||||
|
||||
private var food: FoodRecord? = null
|
||||
|
||||
/** 采集模式下通过搜索页回填的 foodId */
|
||||
private var foodId: String? = null
|
||||
|
||||
/** 来源页面标识,HOME 时返回跳转 SamplingListActivity */
|
||||
private var pageFrom: String? = null
|
||||
|
||||
private var goodsList: MutableList<CookFoodGoodsEntity>? = null
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@@ -64,100 +77,104 @@ class PrepareCookActivity : BaseActivity() {
|
||||
binding = ActivityPrepareCookBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setHeaderBackground()
|
||||
pageFrom = intent.getStringExtra(PAGE_FROM)
|
||||
food = intent.extras?.getSerializable(FOOD_ITEM) as FoodRecord?
|
||||
|
||||
val isSamplingMode = SpTool.cookMode == 1
|
||||
val titleText = if (isSamplingMode) "菜品采集" else "菜品制作"
|
||||
setTitleBar(titleBarAction = {
|
||||
it.visible()
|
||||
}, titleAction = {
|
||||
it.text = "菜品制作"
|
||||
it.text = titleText
|
||||
}, rightIconActon = {
|
||||
it.gone()
|
||||
it.setImageResource(R.drawable.ic_setting)
|
||||
it.setOnClickListener {
|
||||
//startActivity<DeviceSettingActivity>()
|
||||
}
|
||||
}, backAction = {
|
||||
it.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
})
|
||||
food = intent.extras?.getSerializable(FOOD_ITEM) as FoodRecord?
|
||||
binding.tvDishName.text = food?.foodName ?: ""
|
||||
|
||||
// 根据 cookMode 设置搜索栏可编辑性
|
||||
if (isSamplingMode) {
|
||||
// 采集模式:可编辑,支持搜索
|
||||
val foodName = intent.getStringExtra(FOOD_NAME)
|
||||
binding.etInputDish.setText(foodName ?: food?.foodName ?: "")
|
||||
binding.ivDishSearch.visible()
|
||||
} else {
|
||||
// 制作模式:不可编辑,仅展示菜名
|
||||
binding.etInputDish.setText(food?.foodName ?: "")
|
||||
binding.etInputDish.isFocusable = false
|
||||
binding.etInputDish.isFocusableInTouchMode = false
|
||||
binding.ivDishSearch.gone()
|
||||
}
|
||||
|
||||
addViewClickListener()
|
||||
addBackKeyListener()
|
||||
|
||||
initCamera(binding.flCameraContainer)
|
||||
initRecyclerView()
|
||||
|
||||
getDishDetail()
|
||||
if (!isSamplingMode) {
|
||||
getDishDetail()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addViewClickListener() {
|
||||
WeightUtil.addWeightListener(
|
||||
weightKey = TAG,
|
||||
getWeight = { address, state, weight ->
|
||||
//Log.d(TAG, "addViewClickListener: address=$address,state=$state,weight=$weight")
|
||||
if (address == AddressUtil.ONE) {
|
||||
binding.tvDishPartWeight.text = "${weight}"
|
||||
if (state == WeightUtil.STATE_STABLE) {
|
||||
if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) {
|
||||
runOnUiThread {
|
||||
recognizeFood(weight)
|
||||
}
|
||||
}
|
||||
})
|
||||
binding.ivWeightClear.setOnClickListener {
|
||||
WeightUtil.tareTwo(AddressUtil.ONE)
|
||||
|
||||
if (SpTool.cookMode == 1) {
|
||||
// 采集模式:绑定搜索栏交互
|
||||
binding.ivDishSearch.setOnClickListener { v -> jumpSearch(v) }
|
||||
binding.etInputDish.addOnActionSearchListener { jumpSearch(binding.etInputDish) }
|
||||
}
|
||||
binding.ivWeightAdd.setOnClickListener { addWeight() }
|
||||
binding.tvAddFood.clickWithDebounce { addFood() }
|
||||
|
||||
binding.btnCook.clickWithDebounce {
|
||||
val count = list.count { it.isSetFinished.not() }
|
||||
if (count > 0) {
|
||||
showRemindDialog()
|
||||
return@clickWithDebounce
|
||||
if (SpTool.cookMode == 1) {
|
||||
// 采集模式:从输入框创建 FoodRecord
|
||||
val showFoodName = binding.etInputDish.text.toString().trim()
|
||||
if (showFoodName.isBlank()) {
|
||||
toast("菜品名称为空")
|
||||
return@clickWithDebounce
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
toast("菜品构成信息未设置")
|
||||
return@clickWithDebounce
|
||||
}
|
||||
val foodRecord = FoodRecord()
|
||||
binding.etInputDish.let {
|
||||
if (it.tag != null && it.tag.toString() == it.text.toString()) {
|
||||
foodRecord.foodId = foodId
|
||||
}
|
||||
}
|
||||
foodRecord.foodName = showFoodName
|
||||
foodRecord.cookMode = 1
|
||||
Log.d(TAG, "goToSubmit: goodsList:${list.toJsonString()}")
|
||||
startActivity<SubmitFoodActivity> {
|
||||
putExtra(SubmitFoodActivity.GOODS_LIST, list as Serializable)
|
||||
putExtra(SubmitFoodActivity.FOOD_ITEM, foodRecord as Serializable)
|
||||
}
|
||||
} else {
|
||||
// 制作模式:检查食材是否全部设置完成
|
||||
val count = list.count { it.isSetFinished.not() }
|
||||
if (count > 0) {
|
||||
showRemindDialog()
|
||||
return@clickWithDebounce
|
||||
}
|
||||
openSubmitPage()
|
||||
}
|
||||
openSubmitPage()
|
||||
}
|
||||
binding.rgCook.setOnCheckedChangeListener { group, checkedId ->
|
||||
if (clickIndex < 0 || clickIndex >= list.size) return@setOnCheckedChangeListener
|
||||
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 addWeight() {
|
||||
if (clickIndex == -1) {
|
||||
toast("请选择菜品构成")
|
||||
return
|
||||
}
|
||||
val clickItem = list[clickIndex]
|
||||
clickItem.run {
|
||||
if (isNewDishType && materialType != 1 && materialType != 2) {
|
||||
toast("请选择主辅材类型")
|
||||
return
|
||||
}
|
||||
}
|
||||
val weight = binding.tvDishPartWeight.text.toString().toDouble()
|
||||
if (weight <= 0.toDouble()) {
|
||||
toast("食材用量需要大于0")
|
||||
return
|
||||
}
|
||||
Log.d(TAG, "addViewClickListener->useRealWeight=$weight")
|
||||
clickItem.run {
|
||||
useWeight = weight
|
||||
isOriginalData = false
|
||||
isSetFinished = true
|
||||
dishPartAdapter.notifyItemChanged(clickIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private val isTakingPhoto = AtomicBoolean(false)
|
||||
private var isRecognizeOpen = false
|
||||
|
||||
// 页面可见时允许识别,onPause 后禁止,onResume 后恢复
|
||||
private var isRecognizeEnabled = true
|
||||
private var lastPhotoUri: Uri? = null
|
||||
@@ -185,33 +202,24 @@ class PrepareCookActivity : BaseActivity() {
|
||||
|
||||
/**
|
||||
* 菜品选择回调
|
||||
* - list 中不含该 goodsId:直接新增,isNewDishType = true
|
||||
* - list 中已含该 goodsId:累加 useWeight
|
||||
*/
|
||||
private val foodSelectCallback: (CookFoodGoodsEntity) -> Unit = foodSelectCallback@{ item ->
|
||||
val filterResult = list.firstOrNull { it.goodsId == item.goodsId }
|
||||
if (filterResult != null) {
|
||||
toast("不允许重复添加同一食材")
|
||||
return@foodSelectCallback
|
||||
private val foodSelectCallback: (CookFoodGoodsEntity) -> Unit = { item ->
|
||||
val existing = list.firstOrNull { it.goodsId == item.goodsId }
|
||||
if (existing != null) {
|
||||
existing.useWeight = (existing.useWeight ?: 0.0) + (item.useWeight ?: 0.0)
|
||||
existing.isSetFinished = true
|
||||
dishPartAdapter.notifyItemChanged(list.indexOf(existing))
|
||||
} else {
|
||||
list.add(item.also {
|
||||
it.isNewDishType = true
|
||||
it.isSetFinished = true
|
||||
})
|
||||
val position = list.size - 1
|
||||
dishPartAdapter.notifyItemInserted(position)
|
||||
binding.rvDishPartList.smoothScrollToPosition(position)
|
||||
}
|
||||
list.add(CookFoodGoodsEntity().apply {
|
||||
goodsId = item.goodsId
|
||||
goodsName = item.goodsName
|
||||
// materialType =
|
||||
isNewDishType = true
|
||||
isOriginalData = false
|
||||
useWeight = lastWeight
|
||||
isSetFinished = true
|
||||
})
|
||||
val positon = list.size - 1
|
||||
dishPartAdapter.notifyItemInserted(positon)
|
||||
onFoodItemClick(positon)
|
||||
binding.rvDishPartList.smoothScrollToPosition(positon)
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加食材
|
||||
*/
|
||||
private fun addFood() {
|
||||
FoodSearchDialog(activity = this, onItemSelected = foodSelectCallback).show()
|
||||
}
|
||||
|
||||
private fun openSubmitPage() {
|
||||
@@ -307,9 +315,12 @@ class PrepareCookActivity : BaseActivity() {
|
||||
private var firstReqSize = 0
|
||||
private val list = mutableListOf<CookFoodGoodsEntity>()
|
||||
private val dishPartAdapter by lazy {
|
||||
DishPartAdapter(list).apply {
|
||||
DishPartAdapter(list = list).apply {
|
||||
setOnItemClickListener { _, _, positon ->
|
||||
onFoodItemClick(positon)
|
||||
list.forEachIndexed { index, entity ->
|
||||
entity.isItemClicked = index == positon
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
addOnItemChildClickListener(R.id.ivClearIcon) { _, _, positon ->
|
||||
Log.d(TAG, "onFoodItemClick: ${list[positon].toJsonString()}")
|
||||
@@ -327,52 +338,6 @@ class PrepareCookActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜品列表item点击
|
||||
*/
|
||||
private fun onFoodItemClick(positon: Int) {
|
||||
this@PrepareCookActivity.clickIndex = positon
|
||||
list[clickIndex].let { it ->
|
||||
binding.tvDishShowName.run {
|
||||
text = it.goodsName
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
}
|
||||
|
||||
var materialType: String
|
||||
when (it.materialType) {
|
||||
1 -> {
|
||||
materialType = "主材"
|
||||
binding.rgCook.check(R.id.rbDishTypeFirst)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
materialType = "辅材"
|
||||
binding.rgCook.check(R.id.rbDishTypeSecond)
|
||||
}
|
||||
|
||||
else -> {
|
||||
materialType = ""
|
||||
binding.rgCook.clearCheck()
|
||||
}
|
||||
}
|
||||
binding.tvDishType.text = materialType
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
* RecyclerView初始化
|
||||
*/
|
||||
@@ -387,14 +352,10 @@ class PrepareCookActivity : BaseActivity() {
|
||||
dishPartAdapter.notifyItemChanged(position)
|
||||
return@SwipeCallback
|
||||
}
|
||||
// dishPartAdapter.removeAt(position)
|
||||
list.removeAt(position)
|
||||
dishPartAdapter.notifyItemRemoved(position)
|
||||
dishPartAdapter.notifyItemRangeChanged(position, list.size - position)
|
||||
toast("已删除")
|
||||
if (list.isEmpty()) {
|
||||
binding.tvDishShowName.text = ""
|
||||
}
|
||||
})
|
||||
itemTouchHelper.attachToRecyclerView(this)
|
||||
}
|
||||
@@ -428,10 +389,22 @@ class PrepareCookActivity : BaseActivity() {
|
||||
*/
|
||||
private fun addBackKeyListener() {
|
||||
onBackPressedDispatcher.addCallback(this) {
|
||||
val count = list.count { !it.isOriginalData }
|
||||
if (count > 0) {
|
||||
saveDataRemindDialog()
|
||||
return@addCallback
|
||||
if (SpTool.cookMode == 1) {
|
||||
// 采集模式:有新增食材时提示保存
|
||||
if (list.isEmpty().not()) {
|
||||
saveDataRemindDialog()
|
||||
return@addCallback
|
||||
}
|
||||
if (pageFrom == HOME) {
|
||||
startActivity<SamplingListActivity>()
|
||||
}
|
||||
} else {
|
||||
// 制作模式:有未保存数据时提示
|
||||
val count = list.count { !it.isOriginalData }
|
||||
if (count > 0) {
|
||||
saveDataRemindDialog()
|
||||
return@addCallback
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
@@ -443,9 +416,14 @@ class PrepareCookActivity : BaseActivity() {
|
||||
private fun saveDataRemindDialog() {
|
||||
CommonDialog(this)
|
||||
.setTitle("温馨提示")
|
||||
.setContent("您好,当前页面存在尚未保存的数据,确认返回吗?")
|
||||
.setContent("您好,当前页面存在未保存的数据,确认返回吗?")
|
||||
.setNegativeButton("取消")
|
||||
.setPositiveButton("确认") { finish() }
|
||||
.setPositiveButton("确认") {
|
||||
if (SpTool.cookMode == 1 && pageFrom == HOME) {
|
||||
startActivity<SamplingListActivity>()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
.setOnDismissCallback { hideStatusBar() }
|
||||
.show()
|
||||
}
|
||||
@@ -496,12 +474,16 @@ class PrepareCookActivity : BaseActivity() {
|
||||
val foodList = mutableListOf<CookFoodGoodsEntity>()
|
||||
list.forEachIndexed { index, food ->
|
||||
val foodName = food.name.split("WP").first()
|
||||
val foodScore = ((1-food.score) * 100).roundedDecimalPlace(2)
|
||||
foodList.add(CookFoodGoodsEntity(
|
||||
goodsId = index.toString(),
|
||||
goodsName = "${foodName}-${foodScore}%",
|
||||
foodId = index.toString()
|
||||
))
|
||||
foodList.add(
|
||||
CookFoodGoodsEntity(
|
||||
goodsId = "${food.id}",
|
||||
goodsName = foodName,
|
||||
foodId = index.toString()
|
||||
).also {
|
||||
it.foodScore = ((1 - food.score) * 10000).toInt()
|
||||
it.isOriginalData = false
|
||||
}
|
||||
)
|
||||
}
|
||||
FoodRecognizeActivity.start(
|
||||
activity = this,
|
||||
@@ -511,7 +493,26 @@ class PrepareCookActivity : BaseActivity() {
|
||||
)
|
||||
isRecognizeOpen = true
|
||||
isTakingPhoto.set(false)
|
||||
lastWeight = currentWeight
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转食物搜索页(采集模式专用)
|
||||
* @param v 触发搜索的 View,用于收起键盘
|
||||
*/
|
||||
private fun jumpSearch(v: View) {
|
||||
val intent = Intent(this, FoodSearchActivity::class.java).apply {
|
||||
putExtra(FoodSearchActivity.FOOD_NAME, binding.etInputDish.text.toString().trim())
|
||||
}
|
||||
startActivity(intent) {
|
||||
foodId = it?.getStringExtra(FoodSearchActivity.FOOD_ID)
|
||||
val name = it?.getStringExtra(FoodSearchActivity.FOOD_NAME)
|
||||
binding.etInputDish.run {
|
||||
setText(name)
|
||||
tag = name
|
||||
setSelection(text.length)
|
||||
}
|
||||
}
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,8 +120,8 @@ class SamplingListActivity : BaseActivity() {
|
||||
}
|
||||
return
|
||||
}
|
||||
startActivity<DishSamplingActivity> {
|
||||
putExtra(DishSamplingActivity.FOOD_NAME, item.foodName)
|
||||
startActivity<PrepareCookActivity> {
|
||||
putExtra(PrepareCookActivity.FOOD_NAME, item.foodName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ class SamplingListActivity : BaseActivity() {
|
||||
private fun addViewListener() {
|
||||
binding.btnAddSampling.setOnClickListener {
|
||||
judgeDeviceConfig {
|
||||
startActivity<DishSamplingActivity>()
|
||||
startActivity<PrepareCookActivity>()
|
||||
}
|
||||
}
|
||||
binding.refreshLayout.setOnRefreshListener {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.shuwei.dish.match.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@@ -45,6 +47,13 @@ class SlaveActivity : BaseActivity() {
|
||||
/** 已连接的主设备数量(有连接即代表主设备在线) */
|
||||
private var masterConnected = false
|
||||
|
||||
/** 各秤地址的上一次重量快照,用于计算 delta */
|
||||
private val weightSnapshot = mutableMapOf<Int, Double>()
|
||||
/** 主线程 Handler,用于延迟清除高亮 */
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
/** 当前高亮清除任务,新高亮触发时取消旧任务 */
|
||||
private var clearHighlightRunnable: Runnable? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivitySlaveBinding.inflate(layoutInflater)
|
||||
@@ -134,9 +143,19 @@ class SlaveActivity : BaseActivity() {
|
||||
/**
|
||||
* 监听本机 WeightUtil 回调,实时刷新秤列表
|
||||
* 22/18个秤走网格 adapter,其余走线性列表
|
||||
* 秤稳定且重量增加超过阈值时,高亮对应格子,15秒后自动恢复
|
||||
*/
|
||||
private fun listenLocalScales() {
|
||||
WeightUtil.addWeightListener(TAG) { address, state, weight ->
|
||||
// 重量快照与高亮判断(在回调线程计算,不涉及 UI)
|
||||
val baseline = weightSnapshot[address]
|
||||
val shouldHighlight = baseline != null
|
||||
&& state == WeightUtil.STATE_STABLE
|
||||
&& (weight - baseline) > WEIGHT_DELTA_THRESHOLD
|
||||
if (baseline == null || state == WeightUtil.STATE_STABLE) {
|
||||
weightSnapshot[address] = weight
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
when {
|
||||
scale22Adapter != null -> {
|
||||
@@ -167,6 +186,19 @@ class SlaveActivity : BaseActivity() {
|
||||
linearAdapter.submitList(list)
|
||||
}
|
||||
}
|
||||
|
||||
// 触发格子高亮
|
||||
if (shouldHighlight) {
|
||||
clearHighlightRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||
val pos22 = ScaleDeviceConfig.SCALE_ORDER_22.indexOf(address)
|
||||
val pos18 = ScaleDeviceConfig.SCALE_ORDER_18.indexOf(address)
|
||||
scale22Adapter?.highlightPosition(pos22)
|
||||
scale18Adapter?.highlightPosition(pos18)
|
||||
clearHighlightRunnable = Runnable {
|
||||
scale22Adapter?.clearHighlight()
|
||||
scale18Adapter?.clearHighlight()
|
||||
}.also { mainHandler.postDelayed(it, HIGHLIGHT_DURATION_MS) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,11 +218,16 @@ class SlaveActivity : BaseActivity() {
|
||||
override fun onDestroy() {
|
||||
ScaleServiceManager.onMasterConnectionChanged = null
|
||||
WeightUtil.removeWeightListener(TAG)
|
||||
clearHighlightRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "SlaveActivity"
|
||||
/** 重量增加阈值(克),超过此值才触发高亮 */
|
||||
private const val WEIGHT_DELTA_THRESHOLD = 10.0
|
||||
/** 高亮自动恢复时间(毫秒) */
|
||||
private const val HIGHLIGHT_DURATION_MS = 15_000L
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,8 +47,8 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
private val adapter22 by lazy { buildAdapter22() }
|
||||
private val adapter18 by lazy { Seasoning18GridAdapter() }
|
||||
|
||||
/** 各秤地址的上一次重量快照,用于计算 delta */
|
||||
private val weightSnapshot = mutableMapOf<Int, Double>()
|
||||
/** 各秤的上一次重量快照,key 格式 "{deviceId}#{address}",用于计算 delta */
|
||||
private val weightSnapshot = mutableMapOf<String, Double>()
|
||||
/** 主线程 Handler,用于延迟清除高亮 */
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
/** 当前高亮清除任务,新高亮触发时取消旧任务 */
|
||||
@@ -161,7 +161,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
allScalesFlow.collect { scaleMap ->
|
||||
scaleMap.forEach { (key, data) ->
|
||||
val snapshotKey = data.address + data.deviceId.hashCode() * 1000
|
||||
val snapshotKey = "${data.deviceId}#${data.address}"
|
||||
val baseline = weightSnapshot[snapshotKey]
|
||||
if (baseline == null) {
|
||||
// 首次收到:记录基准
|
||||
@@ -187,11 +187,12 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
} else {
|
||||
// 子设备:注册本机 WeightUtil 监听,触发后通过 broadcastEvent 通知主设备
|
||||
WeightUtil.addWeightListener(TAG) { address, state, weight ->
|
||||
val baseline = weightSnapshot[address]
|
||||
val snapshotKey = "${GlobalData.deviceId}#$address"
|
||||
val baseline = weightSnapshot[snapshotKey]
|
||||
Log.d(TAG, "onWeight: address=$address state=$state weight=$weight baseline=$baseline")
|
||||
|
||||
if (baseline == null) {
|
||||
weightSnapshot[address] = weight
|
||||
weightSnapshot[snapshotKey] = weight
|
||||
return@addWeightListener
|
||||
}
|
||||
|
||||
@@ -201,12 +202,12 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
when {
|
||||
// 仅在秤稳定后判断增量,避免取走物品时手部冲力造成误触发
|
||||
state == WeightUtil.STATE_STABLE && delta > WEIGHT_DELTA_THRESHOLD -> {
|
||||
weightSnapshot[address] = weight
|
||||
weightSnapshot[snapshotKey] = weight
|
||||
Log.d(TAG, "onWeight: 触发高亮 address=$address delta=$delta")
|
||||
triggerHighlight(GlobalData.deviceId, address, delta)
|
||||
}
|
||||
state == WeightUtil.STATE_STABLE -> {
|
||||
weightSnapshot[address] = weight
|
||||
weightSnapshot[snapshotKey] = weight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.shuwei.dish.match.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.wabon.wbintelligenthardwaresdk.api.SensorScale;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 修复 SensorScale 地址编码 bug 的子类。
|
||||
*
|
||||
* 问题根因:SensorScale.zeroTwo / tareTwo 内部使用
|
||||
* String command = address + "630603";
|
||||
* 将 int 地址直接拼接为十进制字符串,再整体按十六进制解析成字节。
|
||||
* 对于地址 1-9,十进制 == 十六进制,偶然正确;
|
||||
* 对于地址 10+,十进制 "10" 被解析为 0x10(=16),命中错误的物理秤。
|
||||
*
|
||||
* 修复方式:重写这两个方法,将地址先格式化为两位十六进制字符串(如 10 → "0A"),
|
||||
* 再拼接命令码,通过反射调用父类私有方法 suspendSendThread 和 sumHex 发送。
|
||||
*/
|
||||
public class FixedSensorScale extends SensorScale {
|
||||
|
||||
private static final String TAG = "FixedSensorScale";
|
||||
|
||||
public FixedSensorScale(OnScaleResult result) {
|
||||
super(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写清零命令,修复地址编码:十进制地址 → 两位十六进制字符串。
|
||||
* 例:address=10 → "0A630603",发送字节 0x0A(正确),而非原来的 0x10(错误)。
|
||||
*
|
||||
* @param listener 操作成功回调
|
||||
* @param address 秤地址(来自 onGetWeight 回调的十进制值)
|
||||
*/
|
||||
@Override
|
||||
public void zeroTwo(OperateSuccessListener listener, int address) {
|
||||
sendFixedCommand(listener, address, "630603", "zeroTwo");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写去皮命令,修复地址编码,逻辑同 zeroTwo。
|
||||
*
|
||||
* @param listener 操作成功回调
|
||||
* @param address 秤地址
|
||||
*/
|
||||
@Override
|
||||
public void tareTwo(OperateSuccessListener listener, int address) {
|
||||
sendFixedCommand(listener, address, "630601", "tareTwo");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用发送逻辑:将地址格式化为两位十六进制后拼接命令码,
|
||||
* 通过反射调用父类私有方法 sumHex 计算校验和,再调用 suspendSendThread 发送。
|
||||
*
|
||||
* @param listener 操作成功回调
|
||||
* @param address 秤地址(十进制)
|
||||
* @param commandCode 命令码(十六进制字符串,如 "630603")
|
||||
* @param methodName 调用方名称,仅用于日志
|
||||
*/
|
||||
private void sendFixedCommand(OperateSuccessListener listener, int address,
|
||||
String commandCode, String methodName) {
|
||||
try {
|
||||
// 将十进制地址转为两位十六进制字符串:10 → "0A",1 → "01"
|
||||
String hexAddress = String.format("%02X", address);
|
||||
String command = hexAddress + commandCode;
|
||||
Log.d(TAG, methodName + ", address=" + address
|
||||
+ ", hexAddress=" + hexAddress + ", command=" + command);
|
||||
|
||||
// 反射调用 sumHex(String) 计算校验和
|
||||
Method sumHexMethod = SensorScale.class.getDeclaredMethod("sumHex", String.class);
|
||||
sumHexMethod.setAccessible(true);
|
||||
String checksum = (String) sumHexMethod.invoke(this, command);
|
||||
|
||||
// 反射调用 suspendSendThread(String) 发送完整命令帧
|
||||
Method suspendMethod = SensorScale.class.getDeclaredMethod(
|
||||
"suspendSendThread", String.class);
|
||||
suspendMethod.setAccessible(true);
|
||||
suspendMethod.invoke(this, command + checksum);
|
||||
|
||||
// 保存回调(通过反射写入父类私有字段 mOperateSuccessListener)
|
||||
java.lang.reflect.Field listenerField = SensorScale.class
|
||||
.getDeclaredField("mOperateSuccessListener");
|
||||
listenerField.setAccessible(true);
|
||||
listenerField.set(this, listener);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, methodName + " 反射调用失败: address=" + address, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ public class Weigher2 {
|
||||
public static final int ERR_003 = 1003;
|
||||
public static final int ERR_004 = 1004;
|
||||
public static final int ERR_PCB_NOT_SUPPORT = 2000;
|
||||
private static SensorScale mSensorScale;
|
||||
private static FixedSensorScale mSensorScale;
|
||||
// private static String mDevicePort = "/dev/ttyS4";
|
||||
private static String mDevicePort = "/dev/ttyS7";
|
||||
private static boolean mConnect = false;
|
||||
@@ -40,8 +40,8 @@ public class Weigher2 {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
String var0;
|
||||
if ((var0 = Build.MODEL) == "pcb_941") {
|
||||
String var0 = Build.MODEL;
|
||||
if ("pcb_941".equals(var0)) {
|
||||
Log.w(TAG, "pcb not support, " + var0);
|
||||
Listener var1;
|
||||
if ((var1 = mListener) != null) {
|
||||
@@ -51,7 +51,7 @@ public class Weigher2 {
|
||||
} else {
|
||||
System.init();
|
||||
initScale();
|
||||
if (var0 == "pcb_908") {
|
||||
if ("pcb_908".equals(var0)) {
|
||||
// mDevicePort = "/dev/ttyS4";
|
||||
mDevicePort = "/dev/ttyS7";
|
||||
}
|
||||
@@ -76,8 +76,8 @@ public class Weigher2 {
|
||||
}
|
||||
|
||||
public static void config() {
|
||||
String var0;
|
||||
if ((var0 = Build.MODEL) == "pcb_941") {
|
||||
String var0 = Build.MODEL;
|
||||
if ("pcb_941".equals(var0)) {
|
||||
Log.w(TAG, "pcb not support, " + var0);
|
||||
Listener var2;
|
||||
if ((var2 = mListener) != null) {
|
||||
@@ -402,7 +402,8 @@ public class Weigher2 {
|
||||
}
|
||||
};
|
||||
//.<init>();
|
||||
mSensorScale = new SensorScale(var0);
|
||||
// 使用修复版子类,解决地址 ≥ 10 时 zeroTwo/tareTwo 编码错误的问题
|
||||
mSensorScale = new FixedSensorScale(var0);
|
||||
}
|
||||
|
||||
public static void setNoPull485Pin(boolean noPull) {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.shuwei.dish.match.utils
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace
|
||||
//import com.aithings.Weigher
|
||||
@@ -21,6 +19,7 @@ object WeightUtil {
|
||||
val weightFuncMap: ConcurrentHashMap<String, WeightCallback?> = ConcurrentHashMap()
|
||||
|
||||
fun init() {
|
||||
SensorScale.isLog = true
|
||||
Weigher2.init()
|
||||
Weigher2.setListener(object : WeightListenerImpl() {
|
||||
override fun onInit(connect: Boolean) {
|
||||
@@ -28,6 +27,16 @@ object WeightUtil {
|
||||
isConnected = connect
|
||||
}
|
||||
|
||||
override fun onTare() {
|
||||
super.onTare()
|
||||
Log.d(TAG, "tareTwo,onTare 回调触发")
|
||||
}
|
||||
|
||||
override fun onZero() {
|
||||
super.onZero()
|
||||
Log.d(TAG, "tareTwo,onZero 回调触发")
|
||||
}
|
||||
|
||||
override fun onGetWeight(address: Int, state: Int, weight: Double) {
|
||||
super.onGetWeight(address, state, weight)
|
||||
val stateStr = when (state) {
|
||||
@@ -69,16 +78,12 @@ object WeightUtil {
|
||||
|
||||
fun tareTwo(address: Int) {
|
||||
try {
|
||||
//Weigher2.tareTwo(address)
|
||||
Log.d(TAG, "tareTwo,执行清零操作: address=$address")
|
||||
// SDK 内部自动管理总线,直接发送清零命令
|
||||
Weigher2.zeroTwo(address)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun runOnUiThread(action: () -> Unit) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
action()
|
||||
Log.e(TAG, "tareTwo,执行清零异常: address=$address, error=${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +105,7 @@ open class WeightListenerImpl : Weigher2.Listener {
|
||||
}
|
||||
|
||||
override fun onZero() {
|
||||
Log.d("WeightUtil", "zero ok")
|
||||
Log.d("WeightUtil", "tareTwo,zero ok")
|
||||
}
|
||||
|
||||
override fun onTare() {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
@@ -58,11 +58,12 @@
|
||||
android:textSize="32sp" />
|
||||
|
||||
<!-- 更换食材 -->
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
<TextView
|
||||
android:id="@+id/btnChangeFood"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="90dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/shape_green_bg"
|
||||
android:text="更换食材"
|
||||
android:textColor="@color/white"
|
||||
@@ -70,12 +71,13 @@
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 取消 -->
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
<TextView
|
||||
android:id="@+id/btnCancel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="90dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/shape_white_12_corners"
|
||||
android:text="取消"
|
||||
android:textColor="@color/black333"
|
||||
|
||||
@@ -7,214 +7,52 @@
|
||||
android:orientation="vertical"
|
||||
tools:background="@drawable/bg_other_page">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDishName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:background="@drawable/shape_white_30_corners"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="雪菜烧豆腐" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llSearchBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="30dp"
|
||||
android:background="@drawable/shape_white_30_corners"
|
||||
android:orientation="vertical">
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="109dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id="@+id/etInputDish"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginHorizontal="28dp"
|
||||
android:layout_weight="1"
|
||||
android:autofillHints=""
|
||||
android:background="@color/white"
|
||||
android:gravity="center"
|
||||
android:hint="@string/dish_search_hint"
|
||||
android:inputType="text"
|
||||
android:imeOptions="actionSearch"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="3dp"
|
||||
android:textColor="@color/black333"
|
||||
android:textColorHint="@color/gray_c8"
|
||||
android:textSize="40sp"
|
||||
tools:ignore="TextFields" />
|
||||
|
||||
<!-- <TextView-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_weight="1"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_marginStart="30dp"-->
|
||||
<!-- android:text="食材名称"-->
|
||||
<!-- android:textColor="@color/black666"-->
|
||||
<!-- android:textSize="28sp" />-->
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDishShowName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="30sp"
|
||||
android:textColorHint="@color/black666"
|
||||
android:hint="食材名称"
|
||||
tools:text="" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDishType"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:textColor="@color/black999"
|
||||
android:textSize="26sp"
|
||||
android:layout_marginEnd="30dp"
|
||||
tools:text="" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:id="@+id/dividerDishType"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
app:dividerColor="@color/gray_eb"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llDishType"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="113dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:text="@string/dish_from_type"
|
||||
android:textColor="@color/black666"
|
||||
android:textSize="28sp" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rgCook"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:gravity="center_vertical|end"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbDishTypeFirst"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="30dp"
|
||||
android:background="@color/white"
|
||||
android:button="@null"
|
||||
android:drawableStart="@drawable/selector_dish_type"
|
||||
android:drawablePadding="30dp"
|
||||
android:gravity="center"
|
||||
android:paddingStart="30dp"
|
||||
android:paddingEnd="30dp"
|
||||
android:text="@string/dish_type_first"
|
||||
android:textColor="@color/dish_type_font"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rbDishTypeSecond"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="30dp"
|
||||
android:background="@color/white"
|
||||
android:button="@null"
|
||||
android:checked="false"
|
||||
android:drawableStart="@drawable/selector_dish_type"
|
||||
android:drawablePadding="30dp"
|
||||
android:gravity="center"
|
||||
android:paddingStart="30dp"
|
||||
android:paddingEnd="30dp"
|
||||
android:text="@string/dish_type_second"
|
||||
android:textColor="@color/dish_type_font"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
app:dividerColor="@color/gray_eb" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:text="@string/dish_part_weight_remind"
|
||||
android:textColor="@color/black666"
|
||||
android:textSize="26sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDishPartWeight"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_weight="1"
|
||||
android:autofillHints=""
|
||||
android:background="@drawable/shape_white_f6_10_corners"
|
||||
android:gravity="center"
|
||||
android:hint="-"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text=""
|
||||
android:textColor="@color/dish_green"
|
||||
android:textColorHint="@color/gray_d6"
|
||||
android:textSize="60sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivWeightClear"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="90dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:src="@drawable/ic_weight_clear"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivWeightAdd"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="90dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:src="@drawable/ic_weight_add"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="39dp"
|
||||
android:layout_marginBottom="39dp"
|
||||
android:text="@string/dish_weight_set_remind"
|
||||
android:textColor="@color/black999"
|
||||
android:textSize="26sp" />
|
||||
<ImageView
|
||||
android:id="@+id/ivDishSearch"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:visibility="gone"
|
||||
android:src="@drawable/ic_search_gray"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:layout_marginHorizontal="30dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_white_30_corners"
|
||||
android:orientation="vertical">
|
||||
@@ -237,17 +75,6 @@
|
||||
android:textColor="@color/black666"
|
||||
android:textSize="28sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAddFood"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:drawablePadding="16dp"
|
||||
android:padding="10dp"
|
||||
android:text="@string/add_food"
|
||||
android:textColor="@color/dish_green"
|
||||
android:textSize="26sp"
|
||||
app:drawableEndCompat="@drawable/ic_food_add" />
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
android:id="@+id/ivClearIcon"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="60dp"
|
||||
android:src="@drawable/ic_dish_clear"
|
||||
android:src="@drawable/ic_delete"
|
||||
android:layout_marginEnd="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
@@ -18,4 +18,18 @@
|
||||
android:ellipsize="end"
|
||||
android:background="@drawable/shape_white_12_corners"/>
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/tvFoodScore"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black666"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
tools:text="100%"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:visibility="gone"/>
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
Reference in New Issue
Block a user