refactor(ui): 重构采样模式界面和数据处理逻辑

- 将 RadioButton 替换为 CheckedTextView 并调整布局结构
- 添加安全索引访问避免数组越界异常
- 优化数据库查询方法增加回调版本
- 更新崩溃处理器重启目标页面
- 添加单按钮对话框支持
- 优化采样模式页面数据加载和刷新逻辑
- 调整重量计算和数据处理流程
- 修复页面跳转和数据传递问题
This commit is contained in:
2026-05-14 14:24:25 +08:00
parent 6392b76ac2
commit 89fff7c2b0
18 changed files with 279 additions and 155 deletions
@@ -86,6 +86,8 @@ class FoodListAdapter(
return@run return@run
} }
// 非烹饪中,采样模式 // 非烹饪中,采样模式
tvDishName.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.dish_green))
clBlock.setBackgroundResource(R.drawable.shape_white_fb_15_corners)
val realTotalWeight = if (totalWeight > 0.0) totalWeight else foodWeight val realTotalWeight = if (totalWeight > 0.0) totalWeight else foodWeight
val showTotalWeight = if (realTotalWeight == 0.0) "-" else df.format(realTotalWeight / 1000.0F) val showTotalWeight = if (realTotalWeight == 0.0) "-" else df.format(realTotalWeight / 1000.0F)
tvDishCount.text = "累计统计:${showTotalWeight}kg(${item.count ?: "-"}次)" tvDishCount.text = "累计统计:${showTotalWeight}kg(${item.count ?: "-"}次)"
@@ -48,6 +48,20 @@ class DbViewModel : ViewModel() {
} }
} }
/**
* 查询本地烹饪中数据(回调版本),结果通过 onResult 直接回调,不经过 StateFlow
* 适合不需要跨生命周期持续监听的一次性查询场景
*/
fun getCookFoodListWithCallback(
cookMode: Int,
dinnerType: String = "0",
onResult: (MutableList<CookFoodEntity>?) -> Unit
) {
viewModelScope.launch {
onResult(rep.getCookFoodList(cookMode, dinnerType))
}
}
/** /**
* 直接返回本地烹饪中数据,供需要串行等待结果的场景使用(如先查库再发网络请求) * 直接返回本地烹饪中数据,供需要串行等待结果的场景使用(如先查库再发网络请求)
*/ */
@@ -115,6 +129,17 @@ class DbViewModel : ViewModel() {
} }
} }
/**
* 接口提交成功后删除本地菜品草稿(异步版本,绑定 viewModelScope
* 与 [markSubmittedAndDelete] 的区别:不是 suspend,内部用 viewModelScope 启动协程,
* 不受调用方 Activity 生命周期影响,适合 singleTask 跳转前触发删除的场景
*/
fun markSubmittedAndDeleteAsync(cookMode: Int, foodId: String, dinnerType: String) {
viewModelScope.launch {
markSubmittedAndDelete(cookMode, foodId, dinnerType)
}
}
/** /**
* 接口提交成功后删除本地菜品草稿 * 接口提交成功后删除本地菜品草稿
* 与 [deleteCookFoodAndGoods] 的区别:主表 submitState 会被置 1,便于审计区分手动删除与接口删除 * 与 [deleteCookFoodAndGoods] 的区别:主表 submitState 会被置 1,便于审计区分手动删除与接口删除
@@ -26,10 +26,12 @@ open class CommonDialog(
private var negativeText = "取消" private var negativeText = "取消"
private var positiveText = "确认" private var positiveText = "确认"
private var neutralText: String? = null private var neutralText: String? = null
private var singleText: String? = null
private var negativeClick: (() -> Unit)? = null private var negativeClick: (() -> Unit)? = null
// 返回 true 时关闭弹窗,返回 false 时保持弹窗显示(用于校验不通过的场景) // 返回 true 时关闭弹窗,返回 false 时保持弹窗显示(用于校验不通过的场景)
private var positiveClick: (() -> Boolean)? = null private var positiveClick: (() -> Boolean)? = null
private var neutralClick: (() -> Unit)? = null private var neutralClick: (() -> Unit)? = null
private var singleClick: (() -> Unit)? = null
private var dismissCallback: (() -> Unit)? = null private var dismissCallback: (() -> Unit)? = null
// 待添加到 llContent 的自定义 View,在 onCreate 后挂载 // 待添加到 llContent 的自定义 View,在 onCreate 后挂载
private var pendingContentView: View? = null private var pendingContentView: View? = null
@@ -69,6 +71,12 @@ open class CommonDialog(
neutralClick = onClick neutralClick = onClick
} }
/** 设置单按钮文字及点击回调,调用后自动切换为单按钮布局(优先级最高) */
fun setSingleButton(text: String, onClick: (() -> Unit)? = null): CommonDialog = apply {
singleText = text
singleClick = onClick
}
/** 设置弹窗消失回调 */ /** 设置弹窗消失回调 */
fun setOnDismissCallback(callback: () -> Unit): CommonDialog = apply { fun setOnDismissCallback(callback: () -> Unit): CommonDialog = apply {
dismissCallback = callback dismissCallback = callback
@@ -130,6 +138,12 @@ open class CommonDialog(
if (positiveClick?.invoke() != false) dismiss() if (positiveClick?.invoke() != false) dismiss()
} }
// 单按钮点击事件
binding.btnSingle.setOnClickListener {
singleClick?.invoke()
dismiss()
}
setOnDismissListener { dismissCallback?.invoke() } setOnDismissListener { dismissCallback?.invoke() }
// 挂载自定义内容 View,并执行 tvContent 的灵活控制回调 // 挂载自定义内容 View,并执行 tvContent 的灵活控制回调
@@ -148,10 +162,15 @@ open class CommonDialog(
binding.tvContent.visibility = if (contentText.isNullOrEmpty()) View.GONE else View.VISIBLE binding.tvContent.visibility = if (contentText.isNullOrEmpty()) View.GONE else View.VISIBLE
val hasThreeButtons = !neutralText.isNullOrEmpty() val hasThreeButtons = !neutralText.isNullOrEmpty()
binding.layoutButtonsHorizontal.visibility = if (hasThreeButtons) View.GONE else View.VISIBLE val hasSingleButton = !singleText.isNullOrEmpty()
binding.btnSingle.visibility = if (hasSingleButton) View.VISIBLE else View.GONE
binding.layoutButtonsHorizontal.visibility = if (!hasSingleButton && !hasThreeButtons) View.VISIBLE else View.GONE
binding.layoutButtonsVertical.visibility = if (hasThreeButtons) View.VISIBLE else View.GONE binding.layoutButtonsVertical.visibility = if (hasThreeButtons) View.VISIBLE else View.GONE
if (hasThreeButtons) { if (hasSingleButton) {
// 单按钮模式
binding.btnSingle.text = singleText
} else if (hasThreeButtons) {
// 3按钮模式:顶部=取消,中间=中立,底部=确认 // 3按钮模式:顶部=取消,中间=中立,底部=确认
binding.btnTop.text = negativeText binding.btnTop.text = negativeText
binding.btnMiddle.text = neutralText binding.btnMiddle.text = neutralText
@@ -57,7 +57,7 @@ class FoodSearchDialog(
private val adapter = FoodAdapter(list).apply { private val adapter = FoodAdapter(list).apply {
isStateViewEnable = true isStateViewEnable = true
setOnDebouncedItemClick { _, _, position -> setOnDebouncedItemClick { _, _, position ->
val item = list[position] val item = list.getOrNull(position) ?: return@setOnDebouncedItemClick
// 弹出净材种类单选弹窗,确认后再回调并关闭弹窗 // 弹出净材种类单选弹窗,确认后再回调并关闭弹窗
showRawMaterialsDialog( showRawMaterialsDialog(
context = activity, context = activity,
@@ -52,10 +52,11 @@ class SeasoningSelectDialog(
private val adapter = SeasoningSearchAdapter(list).apply { private val adapter = SeasoningSearchAdapter(list).apply {
isStateViewEnable = true isStateViewEnable = true
setOnItemClickListener { _, v, position -> setOnItemClickListener { _, v, position ->
list[position].isClicked = true val item = list.getOrNull(position) ?: return@setOnItemClickListener
item.isClicked = true
notifyItemChanged(position) notifyItemChanged(position)
v.postDelayed({ v.postDelayed({
onItemSelected(list[position]) onItemSelected(item)
dismiss() dismiss()
}, 300) }, 300)
} }
@@ -122,6 +122,21 @@ class NetViewModel(
} }
} }
/**
* 查询采样数据列表(回调版本),结果通过 onResult 直接回调,不经过 StateFlow
* 适合不需要跨生命周期持续监听的一次性查询场景
*/
fun getSamplingListWithCallback(
param: MutableMap<String, Any>,
onLoading: () -> Unit = {},
onResult: (UiState<MutableList<FoodRecord>?>) -> Unit
) {
viewModelScope.launch {
onLoading()
onResult(repository.getSamplingList(param))
}
}
/** /**
* 查询物品信息列表的 UI 状态流(食材/调料共用),UI 层通过 collect 监听 * 查询物品信息列表的 UI 状态流(食材/调料共用),UI 层通过 collect 监听
*/ */
@@ -27,6 +27,7 @@ import com.shuwei.dish.match.utils.ext.gone
import com.shuwei.dish.match.utils.ext.toast import com.shuwei.dish.match.utils.ext.toast
import com.shuwei.dish.match.utils.ext.visible import com.shuwei.dish.match.utils.ext.visible
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.collections.getOrNull
/** /**
* 已采集食材列表页面 * 已采集食材列表页面
@@ -45,7 +46,8 @@ class CollectedFoodActivity : BaseActivity() {
isStateViewEnable = true isStateViewEnable = true
// 点击删除按钮,移除对应食材 // 点击删除按钮,移除对应食材
addOnItemChildClickListener(R.id.ivDelete) { _, _, position -> addOnItemChildClickListener(R.id.ivDelete) { _, _, position ->
showDeleteDialog(foodList[position].foodName) val item = foodList.getOrNull(position) ?: return@addOnItemChildClickListener
showDeleteDialog(item.foodName)
} }
setOnItemClickListener { _, _, _ -> setOnItemClickListener { _, _, _ ->
hideKeyboard() hideKeyboard()
@@ -135,7 +135,7 @@ class FoodRecognizeActivity : BaseActivity() {
private val adapter = FoodAdapter(list).apply { private val adapter = FoodAdapter(list).apply {
setOnItemClickListener { _, _, position -> setOnItemClickListener { _, _, position ->
// rawMaterialsRemind(position) // rawMaterialsRemind(position)
val item = list[position] val item = list.getOrNull(position) ?: return@setOnItemClickListener
list.forEachIndexed { i, it -> it.isClicked = (i == position) } list.forEachIndexed { i, it -> it.isClicked = (i == position) }
// 点击选择时记录当前秤重量 // 点击选择时记录当前秤重量
item.useWeight = currentWeight item.useWeight = currentWeight
@@ -146,7 +146,7 @@ class FoodRecognizeActivity : BaseActivity() {
} }
private fun rawMaterialsRemind(position: Int) { private fun rawMaterialsRemind(position: Int) {
val item = list[position] val item = list.getOrNull(position) ?: return
// 弹出净材种类单选弹窗,确认后再选中该食材 // 弹出净材种类单选弹窗,确认后再选中该食材
showRawMaterialsDialog( showRawMaterialsDialog(
context = this@FoodRecognizeActivity, context = this@FoodRecognizeActivity,
@@ -514,8 +514,10 @@ class FoodRecognizeActivity : BaseActivity() {
if (unstableDialog == null) { if (unstableDialog == null) {
unstableDialog = CommonDialog(this) unstableDialog = CommonDialog(this)
.setTitle("提示") .setTitle("提示")
.setContent("数据不稳定,请重新放置食材后再取走") .setContent("数据不稳定,请放置食材进行重新识别")
.setPositiveButton("确认") .setSingleButton("确认") {
finishWithResult(true)
}
} }
unstableDialog?.show() unstableDialog?.show()
return return
@@ -25,6 +25,7 @@ import com.shuwei.dish.match.utils.ext.toast
import com.shuwei.dish.match.utils.ext.visible import com.shuwei.dish.match.utils.ext.visible
import java.io.Serializable import java.io.Serializable
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.collections.getOrNull
/** /**
* 菜品搜索页面 * 菜品搜索页面
@@ -47,15 +48,16 @@ class FoodSearchActivity : BaseActivity() {
Food2Adapter(list).apply { Food2Adapter(list).apply {
isStateViewEnable = true isStateViewEnable = true
setOnItemClickListener { adapter, view, position -> setOnItemClickListener { adapter, view, position ->
var jumpItem = list.getOrNull(position) ?: return@setOnItemClickListener
if (SpTool.cookMode == 0) { if (SpTool.cookMode == 0) {
val jumpItem = list[position].also { it.dinnerType = dinnerType } jumpItem.dinnerType = dinnerType
startActivity<PrepareFoodActivity> { startActivity<PrepareFoodActivity> {
putExtra(PrepareFoodActivity.FOOD_ITEM, jumpItem as Serializable) putExtra(PrepareFoodActivity.FOOD_ITEM, jumpItem as Serializable)
} }
return@setOnItemClickListener return@setOnItemClickListener
} }
setResult(RESULT_OK, Intent().apply { setResult(RESULT_OK, Intent().apply {
putExtra(FOOD_ITEM, list[position] as Serializable) putExtra(FOOD_ITEM, jumpItem as Serializable)
}) })
finish() finish()
} }
@@ -15,6 +15,7 @@ import com.shuwei.dish.match.utils.SpTool
import com.shuwei.dish.match.utils.ext.startActivity import com.shuwei.dish.match.utils.ext.startActivity
import com.shuwei.dish.match.utils.ext.toast import com.shuwei.dish.match.utils.ext.toast
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.collections.getOrNull
/** /**
* 主页,包括三种模式:制作模式、采样模式、品控模式 * 主页,包括三种模式:制作模式、采样模式、品控模式
@@ -97,7 +98,7 @@ class HomeActivity : BaseActivity() {
private val modeAdapter by lazy { private val modeAdapter by lazy {
HomeModeAdapter(modeList).apply { HomeModeAdapter(modeList).apply {
addOnItemChildClickListener(R.id.layoutCard) { adapter, view, position -> addOnItemChildClickListener(R.id.layoutCard) { adapter, view, position ->
modeList[position].onClick?.invoke() modeList.getOrNull(position)?.onClick?.invoke()
} }
} }
} }
@@ -146,10 +146,10 @@ class PrepareFoodActivity : BaseActivity() {
if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) { if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) {
runOnUiThread { runOnUiThread {
// 首次收到稳定读数时,将其作为初始值(去皮基准) // 首次收到稳定读数时,将其作为初始值(去皮基准)
if (!initialWeightReady) { // if (!initialWeightReady) {
initialWeight = weight // initialWeight = weight
initialWeightReady = true // initialWeightReady = true
} // }
// 净重 = 秤读数 - 初始读数 // 净重 = 秤读数 - 初始读数
val netWeight = weight - initialWeight val netWeight = weight - initialWeight
binding.tvShowWeight.run { binding.tvShowWeight.run {
@@ -227,7 +227,7 @@ class PrepareFoodActivity : BaseActivity() {
private var initialWeight = 0.0 private var initialWeight = 0.0
/** 初始读数是否已从秤获取 */ /** 初始读数是否已从秤获取 */
private var initialWeightReady = false // private var initialWeightReady = false
/** /**
* 重量稳定时触发菜品识别 * 重量稳定时触发菜品识别
@@ -413,8 +413,8 @@ class PrepareFoodActivity : BaseActivity() {
notifyDataSetChanged() notifyDataSetChanged()
} }
addOnItemChildClickListener(R.id.ivClearIcon) { _, _, position -> addOnItemChildClickListener(R.id.ivClearIcon) { _, _, position ->
Log.d(TAG, "onFoodItemClick: ${list[position].toJsonString()}") val item = list.getOrNull(position) ?:return@addOnItemChildClickListener
val item = list[position] Log.d(TAG, "onFoodItemClick: ${item.toJsonString()}")
if (item.isOriginalData) { if (item.isOriginalData) {
// 无重量信息时转为 item 整体点击(触发选中效果) // 无重量信息时转为 item 整体点击(触发选中效果)
if (item.useWeight == null || item.useWeight == 0.0) { if (item.useWeight == null || item.useWeight == 0.0) {
@@ -3,13 +3,12 @@ package com.shuwei.dish.match.ui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.shuwei.dish.match.R import com.shuwei.dish.match.R
import com.shuwei.dish.match.adapter.FoodListAdapter import com.shuwei.dish.match.adapter.FoodListAdapter
@@ -49,23 +48,39 @@ class SamplingModeActivity : BaseActivity() {
setHeaderBackground() setHeaderBackground()
initRecyclerView() initRecyclerView()
addViewListener() addViewListener()
initObserver()
requestData(true) requestData(true)
onBackPressedDispatcher.addCallback(this) { } onBackPressedDispatcher.addCallback(this) { }
} }
/** private fun setTitleBar() {
* 收集 cookFoodListState,将本地烹饪中数据渲染到列表 setTitleBar(titleBarAction = {
*/ it.visible()
private fun initObserver() { }, titleAction = {
lifecycleScope.launch { it.text = "采样历史"
repeatOnLifecycle(Lifecycle.State.STARTED) { }, rightIconActon = {
appViewModel.cookFoodListState.collect { cookFoodEntities -> it.visible()
if (binding.dishRadioGroup.checkedRadioButtonId != R.id.rbSamplingCooking) return@collect it.setImageResource(R.drawable.ic_setting)
it.setOnClickListener {
startActivity<SettingActivity>()
}
}, backAction = {
it.gone()
})
}
@SuppressLint("NotifyDataSetChanged")
fun getCookFoodList() {
//val checkedId = binding.dishRadioGroup.checkedRadioButtonId
// if (checkedId == R.id.rbSamplingCooking) {
// if (binding.rbSamplingCooking.isChecked) {
appViewModel.getCookFoodListWithCallback(cookMode = 1) { cookFoodEntities ->
// 回调期间用户可能已切换 Tab,需再次校验
// if (binding.dishRadioGroup.checkedRadioButtonId != R.id.rbSamplingCooking) return@getCookFoodListWithCallback
if (binding.rbSamplingCooking.isChecked.not()) return@getCookFoodListWithCallback
delayDismissLoading() delayDismissLoading()
if (cookFoodEntities.isNullOrEmpty()) { if (cookFoodEntities.isNullOrEmpty()) {
loadEmptyView() loadEmptyView()
return@collect return@getCookFoodListWithCallback
} }
val tempList = mutableListOf<FoodRecord>() val tempList = mutableListOf<FoodRecord>()
cookFoodEntities.sortedByDescending { DateTimeUtil.convert(dateStr = it.createTime) } cookFoodEntities.sortedByDescending { DateTimeUtil.convert(dateStr = it.createTime) }
@@ -87,64 +102,7 @@ class SamplingModeActivity : BaseActivity() {
setEnableLoadMore(false) setEnableLoadMore(false)
} }
} }
} // }
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
netViewModel.samplingListState.collect { state ->
when (state) {
is UiState.Loading -> showLoading()
is UiState.Success -> {
if (binding.dishRadioGroup.checkedRadioButtonId != R.id.rbSamplingFinished) {
delayDismissLoading()
return@collect
}
loadDishList(state.data)
}
is UiState.Error -> {
if (binding.dishRadioGroup.checkedRadioButtonId != R.id.rbSamplingFinished) {
delayDismissLoading()
return@collect
}
binding.refreshLayout.setEnableRefresh(true)
toast(state.msg)
finishRefresh()
delayDismissLoading()
if (pageNo == 1) loadEmptyView()
}
is UiState.Idle -> {}
}
}
}
}
}
private fun setTitleBar() {
setTitleBar(titleBarAction = {
it.visible()
}, titleAction = {
it.text = "采样历史"
}, rightIconActon = {
it.visible()
it.setImageResource(R.drawable.ic_setting)
it.setOnClickListener {
startActivity<SettingActivity>()
}
}, backAction = {
it.gone()
})
}
fun getCookFoodList() {
val checkedId = binding.dishRadioGroup.checkedRadioButtonId
if (checkedId == R.id.rbSamplingCooking) {
appViewModel.getCookFoodList(cookMode = 1)
}
} }
fun deleteCookFoodAndGoods(foodId: String, dinnerType: String, action: () -> Unit) { fun deleteCookFoodAndGoods(foodId: String, dinnerType: String, action: () -> Unit) {
@@ -157,11 +115,13 @@ class SamplingModeActivity : BaseActivity() {
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent) super.onNewIntent(intent)
val isConfigPage = intent?.getBooleanExtra(IS_CONFIG_PAGE, false) ?: false val isConfigPage = intent?.getBooleanExtra(IS_CONFIG_PAGE, false) ?: false
Log.d(TAG, "onNewIntent, isConfigPage=$isConfigPage")
if (isConfigPage) { if (isConfigPage) {
getCookFoodList() getCookFoodList()
return return
} }
val isCooking = intent?.getBooleanExtra(IS_COOKING, false) ?: false val isCooking = intent?.getBooleanExtra(IS_COOKING, false) ?: false
Log.d(TAG, "onNewIntent, isCooking=$isCooking")
//toast("isCooking=$isCooking") //toast("isCooking=$isCooking")
refreshPage(isCooking) refreshPage(isCooking)
} }
@@ -252,7 +212,8 @@ class SamplingModeActivity : BaseActivity() {
} }
binding.refreshLayout.setOnRefreshListener { binding.refreshLayout.setOnRefreshListener {
pageNo = 1 pageNo = 1
if (binding.dishRadioGroup.checkedRadioButtonId == R.id.rbSamplingFinished) { // if (binding.dishRadioGroup.checkedRadioButtonId == R.id.rbSamplingFinished) {
if (binding.rbSamplingFinished.isChecked) {
getSamplingList() getSamplingList()
} else { } else {
finishRefresh() finishRefresh()
@@ -260,30 +221,41 @@ class SamplingModeActivity : BaseActivity() {
} }
} }
binding.refreshLayout.setOnLoadMoreListener { binding.refreshLayout.setOnLoadMoreListener {
if (binding.dishRadioGroup.checkedRadioButtonId == R.id.rbSamplingFinished) { // if (binding.dishRadioGroup.checkedRadioButtonId == R.id.rbSamplingFinished) {
if (binding.rbSamplingFinished.isChecked) {
getSamplingList() getSamplingList()
} else { } else {
finishRefresh() finishRefresh()
} }
} }
binding.rbSamplingCooking.setOnClickListener { binding.rbSamplingCooking.let {
it.setOnClickListener { _->
// Log.d(TAG, "addViewListener: cooking:${binding.rbSamplingCooking.isChecked}") // Log.d(TAG, "addViewListener: cooking:${binding.rbSamplingCooking.isChecked}")
if (it.tag == true) { // if (it.tag == true) {
if (it.isChecked) {
return@setOnClickListener return@setOnClickListener
} }
binding.rbSamplingCooking.isChecked = true
binding.rbSamplingFinished.isChecked = false
binding.rbSamplingCooking.tag = binding.rbSamplingCooking.isChecked
binding.rbSamplingFinished.tag = binding.rbSamplingFinished.isChecked
requestData(true) requestData(true)
binding.rbSamplingCooking.tag = binding.rbSamplingCooking.isChecked
binding.rbSamplingFinished.tag = binding.rbSamplingFinished.isChecked
} }
binding.rbSamplingFinished.setOnClickListener { }
binding.rbSamplingFinished.let {
it.setOnClickListener { _->
// Log.d(TAG, "addViewListener: finish:${binding.rbSamplingFinished.isChecked}") // Log.d(TAG, "addViewListener: finish:${binding.rbSamplingFinished.isChecked}")
if (it.tag == true) { // if (it.tag == true) {
if (it.isChecked) {
return@setOnClickListener return@setOnClickListener
} }
requestData(false) binding.rbSamplingCooking.isChecked = false
binding.rbSamplingFinished.isChecked = true
binding.rbSamplingCooking.tag = binding.rbSamplingCooking.isChecked binding.rbSamplingCooking.tag = binding.rbSamplingCooking.isChecked
binding.rbSamplingFinished.tag = binding.rbSamplingFinished.isChecked binding.rbSamplingFinished.tag = binding.rbSamplingFinished.isChecked
requestData(false)
}
} }
} }
@@ -292,13 +264,39 @@ class SamplingModeActivity : BaseActivity() {
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun getSamplingList() { fun getSamplingList() {
netViewModel.getSamplingList( netViewModel.getSamplingListWithCallback(
param = mutableMapOf( param = mutableMapOf(
"pageNum" to pageNo, "pageNum" to pageNo,
"pageSize" to pageSize, "pageSize" to pageSize,
"placeId" to BaseApp.canteenId "placeId" to BaseApp.canteenId
) ),
) onLoading = { showLoading() }
) { state ->
when (state) {
is UiState.Success -> {
// 回调期间用户可能已切换 Tab,需再次校验
// if (binding.dishRadioGroup.checkedRadioButtonId != R.id.rbSamplingFinished) {
if (binding.rbSamplingFinished.isChecked.not()) {
delayDismissLoading()
return@getSamplingListWithCallback
}
loadDishList(state.data)
}
is UiState.Error -> {
// if (binding.dishRadioGroup.checkedRadioButtonId != R.id.rbSamplingFinished) {
if (binding.rbSamplingFinished.isChecked.not()) {
delayDismissLoading()
return@getSamplingListWithCallback
}
binding.refreshLayout.setEnableRefresh(true)
toast(state.msg)
finishRefresh()
delayDismissLoading()
if (pageNo == 1) loadEmptyView()
}
else -> {}
}
}
} }
private fun finishRefresh() { private fun finishRefresh() {
@@ -336,18 +334,22 @@ class SamplingModeActivity : BaseActivity() {
//dishAdapter.setStateViewLayout(requireContext(), R.layout-sw800dp.layout_empty_view) //dishAdapter.setStateViewLayout(requireContext(), R.layout-sw800dp.layout_empty_view)
binding.refreshLayout.run { binding.refreshLayout.run {
setEnableRefresh(binding.dishRadioGroup.checkedRadioButtonId == R.id.rbSamplingFinished) // setEnableRefresh(binding.dishRadioGroup.checkedRadioButtonId == R.id.rbSamplingFinished)
setEnableRefresh(binding.rbSamplingFinished.isChecked)
setEnableLoadMore(false) setEnableLoadMore(false)
} }
} }
fun refreshPage(isCooking: Boolean) { fun refreshPage(isCooking: Boolean) {
val checkedId = binding.dishRadioGroup.checkedRadioButtonId // val checkedId = binding.dishRadioGroup.checkedRadioButtonId
if (checkedId == R.id.rbSamplingFinished) { // if (checkedId == R.id.rbSamplingFinished) {
if (binding.rbSamplingFinished.isChecked) {
//当前是已采样 //当前是已采样
if (isCooking) { if (isCooking) {
//需要切换到烹饪中 //需要切换到烹饪中
binding.dishRadioGroup.check(R.id.rbSamplingCooking) //binding.dishRadioGroup.check(R.id.rbSamplingCooking)
binding.rbSamplingCooking.isChecked = true
binding.rbSamplingFinished.isChecked = false
requestData(true) requestData(true)
return return
} }
@@ -358,7 +360,9 @@ class SamplingModeActivity : BaseActivity() {
//当前是烹饪中 //当前是烹饪中
if (isCooking.not()) { if (isCooking.not()) {
//需要切换到已采样 //需要切换到已采样
binding.dishRadioGroup.check(R.id.rbSamplingFinished) // binding.dishRadioGroup.check(R.id.rbSamplingFinished)
binding.rbSamplingCooking.isChecked = false
binding.rbSamplingFinished.isChecked = true
requestData(false) requestData(false)
return return
} }
@@ -366,21 +370,17 @@ class SamplingModeActivity : BaseActivity() {
requestData(true) requestData(true)
} }
@SuppressLint("NotifyDataSetChanged")
fun refreshLocalData() { fun refreshLocalData() {
showLoading() showLoading()
appViewModel.resetCookFoodList()
getCookFoodList() getCookFoodList()
} }
private fun requestData(isCooking: Boolean) { private fun requestData(isCooking: Boolean) {
list.clear()
dishAdapter.notifyDataSetChanged()
if (isCooking) { if (isCooking) {
// 清除上次网络请求的残留状态
netViewModel.resetSamplingListState()
refreshLocalData() refreshLocalData()
} else { } else {
// 同理,清除本地数据残留状态
appViewModel.resetCookFoodList()
pageNo = 1 pageNo = 1
getSamplingList() getSamplingList()
} }
@@ -106,7 +106,7 @@ class SubmitFoodActivity : BaseActivity() {
private var initWeight: Double = 0.0 private var initWeight: Double = 0.0
/** initWeight 是否已完成初始化 */ /** initWeight 是否已完成初始化 */
private var initWeightSet: Boolean = false // private var initWeightSet: Boolean = false
@Suppress("unchecked_cast", "DEPRECATION") @Suppress("unchecked_cast", "DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -340,10 +340,10 @@ class SubmitFoodActivity : BaseActivity() {
WeightUtil.addWeightListener(TAG) { address, _, weight -> WeightUtil.addWeightListener(TAG) { address, _, weight ->
if (address == AddressUtil.TWO) { if (address == AddressUtil.TWO) {
// 首次收到数据时记录初始重量 // 首次收到数据时记录初始重量
if (!initWeightSet) { // if (!initWeightSet) {
initWeight = weight // initWeight = weight
initWeightSet = true // initWeightSet = true
} // }
// 实际净重 = 秤读数 - 初始重量 // 实际净重 = 秤读数 - 初始重量
val netWeight = weight - initWeight val netWeight = weight - initWeight
cookFoodEntity.foodWeight = netWeight cookFoodEntity.foodWeight = netWeight
@@ -464,8 +464,9 @@ class SubmitFoodActivity : BaseActivity() {
jumpPage(isSamplingData, false) jumpPage(isSamplingData, false)
return return
} }
lifecycleScope.launch { // 用 viewModelScope 执行删除,不受当前 Activity 生命周期影响
appViewModel.markSubmittedAndDelete( // singleTask 跳转会销毁本 Activity 并取消 lifecycleScope,导致删除被中断
appViewModel.markSubmittedAndDeleteAsync(
cookMode = food!!.cookMode, cookMode = food!!.cookMode,
foodId = food!!.foodId!!, foodId = food!!.foodId!!,
dinnerType = food!!.dinnerType dinnerType = food!!.dinnerType
@@ -473,7 +474,6 @@ class SubmitFoodActivity : BaseActivity() {
dismissLoading() dismissLoading()
jumpPage(isSamplingData, false) jumpPage(isSamplingData, false)
} }
}
private fun jumpPage(isSampling: Boolean, isCooking: Boolean) { private fun jumpPage(isSampling: Boolean, isCooking: Boolean) {
if (isSampling) { if (isSampling) {
@@ -75,7 +75,7 @@ class FoodListFragment : BaseFragment<FragmentFoodListBinding>() {
} }
private fun onItemClick(position: Int) { private fun onItemClick(position: Int) {
val item = list[position] val item = list.getOrNull(position) ?: return
if (item.isCooking) { if (item.isCooking) {
// 烹饪中,跳到称熟重页面 // 烹饪中,跳到称熟重页面
activity.startActivity<SubmitFoodActivity> { activity.startActivity<SubmitFoodActivity> {
@@ -124,12 +124,12 @@ class FoodListFragment : BaseFragment<FragmentFoodListBinding>() {
} }
.show() .show()
} }
// item 点击 // // item 点击
setOnItemClickListener { _, position -> // setOnItemClickListener { _, position ->
if (isAdded && isVisible) { // if (isAdded && isVisible) {
activity.judgeDeviceConfig { onItemClick(position) } // activity.judgeDeviceConfig { onItemClick(position) }
} // }
} // }
adapter = dishAdapter adapter = dishAdapter
} }
addViewListener() addViewListener()
@@ -81,7 +81,7 @@ class VectorCollectionFragment : BaseFragment<FragmentVectorCollectionBinding>()
// 开启空状态视图能力,否则 stateView 赋值不会生效 // 开启空状态视图能力,否则 stateView 赋值不会生效
isStateViewEnable = true isStateViewEnable = true
setOnDebouncedItemClick { _, _, position -> setOnDebouncedItemClick { _, _, position ->
val item = searchList[position] val item = searchList.getOrNull(position) ?: return@setOnDebouncedItemClick
// 弹出净材种类单选弹窗 // 弹出净材种类单选弹窗
showRawMaterialsDialog( showRawMaterialsDialog(
context = requireContext(), context = requireContext(),
@@ -113,7 +113,7 @@ class VectorCollectionFragment : BaseFragment<FragmentVectorCollectionBinding>()
private val vectorAdapter: VectorCollectionAdapter by lazy { private val vectorAdapter: VectorCollectionAdapter by lazy {
VectorCollectionAdapter(vectorList).apply { VectorCollectionAdapter(vectorList).apply {
addOnItemChildClickListener(R.id.ivDelete) { _, _, position -> addOnItemChildClickListener(R.id.ivDelete) { _, _, position ->
vectorList[position].let { vectorList.getOrNull(position)?.let {
it.bitmap = null it.bitmap = null
it.imageVector = null it.imageVector = null
it.imageFile = null it.imageFile = null
@@ -121,11 +121,11 @@ class VectorCollectionFragment : BaseFragment<FragmentVectorCollectionBinding>()
it.isShowCamera = true it.isShowCamera = true
it.isFinish = false it.isFinish = false
it.uploadSuccess = false it.uploadSuccess = false
}
notifyItemChanged(position) notifyItemChanged(position)
} }
} }
} }
}
override fun inflateBinding( override fun inflateBinding(
@@ -11,6 +11,7 @@ import android.os.Looper
import android.os.Process import android.os.Process
import android.util.Log import android.util.Log
import com.shuwei.dish.match.ui.HomeActivity import com.shuwei.dish.match.ui.HomeActivity
import com.shuwei.dish.match.ui.InitActivity
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
@@ -75,7 +76,7 @@ class CrashHandler private constructor(private val context: Context) :
private fun restartApp() { private fun restartApp() {
// 延迟1秒后重启应用 // 延迟1秒后重启应用
Handler(Looper.getMainLooper()).postDelayed({ Handler(Looper.getMainLooper()).postDelayed({
val intent = Intent(context, HomeActivity::class.java).apply { val intent = Intent(context, InitActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} }
@@ -6,14 +6,53 @@
android:orientation="vertical" android:orientation="vertical"
tools:background="@drawable/bg_other_page"> tools:background="@drawable/bg_other_page">
<RadioGroup <!-- <RadioGroup-->
android:id="@+id/dishRadioGroup" <!-- android:id="@+id/dishRadioGroup"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="88dp"-->
<!-- android:layout_marginTop="15dp"-->
<!-- android:orientation="horizontal">-->
<!-- <RadioButton-->
<!-- android:id="@+id/rbSamplingCooking"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="match_parent"-->
<!-- android:layout_marginStart="30dp"-->
<!-- android:layout_weight="1"-->
<!-- android:background="@drawable/breakfast_bg"-->
<!-- android:button="@null"-->
<!-- android:checked="true"-->
<!-- android:gravity="center"-->
<!-- android:text="@string/rb_sampling_cooking"-->
<!-- android:textColor="@color/breakfast_font"-->
<!-- android:textSize="30sp"-->
<!-- android:textStyle="bold" />-->
<!-- <RadioButton-->
<!-- android:id="@+id/rbSamplingFinished"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="match_parent"-->
<!-- android:layout_marginStart="9dp"-->
<!-- android:layout_marginEnd="30dp"-->
<!-- android:layout_weight="1"-->
<!-- android:background="@drawable/breakfast_bg"-->
<!-- android:button="@null"-->
<!-- android:checked="false"-->
<!-- android:gravity="center"-->
<!-- android:text="@string/rb_sampling_finished"-->
<!-- android:textColor="@color/breakfast_font"-->
<!-- android:textSize="30sp"-->
<!-- android:textStyle="bold" />-->
<!-- </RadioGroup>-->
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="88dp" android:layout_height="88dp"
android:layout_marginTop="15dp" android:layout_marginTop="15dp"
android:orientation="horizontal"> android:orientation="horizontal">
<RadioButton <CheckedTextView
android:id="@+id/rbSamplingCooking" android:id="@+id/rbSamplingCooking"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -23,13 +62,14 @@
android:button="@null" android:button="@null"
android:checked="true" android:checked="true"
android:gravity="center" android:gravity="center"
android:textAlignment="center"
android:text="@string/rb_sampling_cooking" android:text="@string/rb_sampling_cooking"
android:textColor="@color/breakfast_font" android:textColor="@color/breakfast_font"
android:textSize="30sp" android:textSize="30sp"
android:textStyle="bold" /> android:textStyle="bold" />
<RadioButton <CheckedTextView
android:id="@+id/rbSamplingFinished" android:id="@+id/rbSamplingFinished"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -40,11 +80,12 @@
android:button="@null" android:button="@null"
android:checked="false" android:checked="false"
android:gravity="center" android:gravity="center"
android:textAlignment="center"
android:text="@string/rb_sampling_finished" android:text="@string/rb_sampling_finished"
android:textColor="@color/breakfast_font" android:textColor="@color/breakfast_font"
android:textSize="30sp" android:textSize="30sp"
android:textStyle="bold" /> android:textStyle="bold" />
</RadioGroup> </LinearLayout>
<LinearLayout <LinearLayout
+13
View File
@@ -53,6 +53,19 @@
android:layout_height="1dp" android:layout_height="1dp"
android:background="@color/gray_eb" /> android:background="@color/gray_eb" />
<!-- 1个按钮时显示(全宽居中) -->
<TextView
android:id="@+id/btnSingle"
android:layout_width="match_parent"
android:layout_height="96dp"
android:background="@drawable/ripple_btn_bottom"
android:gravity="center"
android:textColor="@color/dish_green"
android:textSize="28sp"
android:textStyle="bold"
android:visibility="gone"
tools:text="我知道了" />
<!-- 2个按钮时显示(水平排列) --> <!-- 2个按钮时显示(水平排列) -->
<LinearLayout <LinearLayout
android:id="@+id/layoutButtonsHorizontal" android:id="@+id/layoutButtonsHorizontal"