接口调试、增加人脸识别后主副屏支付金额逻辑、其它优化

This commit is contained in:
2025-12-03 18:40:47 +08:00
parent 29188c5944
commit 8899cae323
34 changed files with 1202 additions and 402 deletions
@@ -16,6 +16,7 @@ import android.view.ViewOutlineProvider
import android.view.ViewTreeObserver
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.arcsoft.face.ErrorInfo
@@ -26,6 +27,7 @@ import com.sw.dualscreen.databinding.PresentationMainScreenBinding
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.maskName
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.request.UserNutritionParam
@@ -33,8 +35,6 @@ import com.sw.dualscreen.model.response.DinnerType
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.UserNutritionData
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.GlideUtils
import com.sw.dualscreen.utils.GsonUtils
import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.LightManager
@@ -55,6 +55,7 @@ import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.math.max
import kotlin.math.roundToInt
class MainScreenPresentation(
@@ -63,7 +64,7 @@ class MainScreenPresentation(
val userViewModel: UserViewModel,
val recognizeViewModel: RecognizeViewModel,
private val onDismissListener: () -> Unit = {}
) : Presentation(activity, display), ViewTreeObserver.OnGlobalLayoutListener {
) : Presentation(activity, display), ViewTreeObserver.OnGlobalLayoutListener {
companion object {
const val TAG = "SubScreenPresentation"
@@ -71,6 +72,7 @@ class MainScreenPresentation(
private lateinit var binding: PresentationMainScreenBinding
private lateinit var stepChangeCallback: (Int) -> Unit
// 当前步骤
var currentStep: Int = 0
@@ -110,11 +112,19 @@ class MainScreenPresentation(
fun updateWeight(weight: Double) {
lastWeight = weight * 1000 // 将千克转成克
Timber.tag(TAG).d("updateWeight lastWeight = $weight, currentStep = $currentStep, isGoStep1 = $isGoStep1")
if ((currentStep == 2) &&
lastWeight <= 5 &&
isGoStep1
) {//人脸识别过程中,秤上物品拿走
Timber.tag(TAG)
.d("updateWeight lastWeight = $weight, currentStep = $currentStep, isGoStep1 = $isGoStep1")
// if (lastWeight <= 5) {
// activity.isAnalyzing = false
// }
if (currentStep == 2 && lastWeight <= 5 && isGoStep1) {
//人脸识别过程中,秤上物品拿走
isGoStep1 = false
activity.runOnUiThread {
Timber.tag(TAG).e("切回step1")
step1FoodRecognizing()
}
} else if (lastWeight <= 5) {
isGoStep1 = false
activity.runOnUiThread {
Timber.tag(TAG).e("切回step1")
@@ -140,6 +150,7 @@ class MainScreenPresentation(
}
calculateNutrition(recognitionWeight - lastWeight)
}
fun setStepChangeCallback(callback: (Int) -> Unit) {
stepChangeCallback = callback
}
@@ -200,10 +211,10 @@ class MainScreenPresentation(
Timber.tag(TAG).d("registerDataChange nutritionData = $it")
userNutritionData = it
if (it == null) return@collect
step3ShowRecognizeResult()
//binding.nutritionInclude.tvUserName.text = it.userName.maskName()
//binding.nutritionInclude.tvRecommendHeat.text = "推荐热量:${it.recommendMin}-${it.recommendMax}"
//updateWeight(lastWeight / 1000)
// step3ShowRecognizeResult()
// //binding.nutritionInclude.tvUserName.text = it.userName.maskName()
// //binding.nutritionInclude.tvRecommendHeat.text = "推荐热量:${it.recommendMin}-${it.recommendMax}"
// //updateWeight(lastWeight / 1000)
}
}
activity.lifecycleScope.launch {
@@ -227,20 +238,22 @@ class MainScreenPresentation(
ToastUtils.showToast("选中物品为空")
return
}
updateFoodInfo(currentFood!!)
// updateFoodInfo(currentFood!!)
foodRecSuccess(currentFood!!)
//foodRecSuccess(currentFood!!)
}
private fun initView() {
// //binding.ivRecImage.let {
// it.outlineProvider = object : ViewOutlineProvider() {
// override fun getOutline(view: View, outline: Outline) {
// outline.setRoundRect(0, 0, view.width, view.height, 12f.dp)
// }
// }
// it.clipToOutline = true
// }
binding.ivRecImage.let {
it.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(0, 0, view.width, view.height, 12f.dp)
}
}
it.clipToOutline = true
}
}
override fun onDisplayRemoved() {
super.onDisplayRemoved()
onDismissListener()
@@ -274,11 +287,46 @@ class MainScreenPresentation(
//updateFoodInfo(foodInfo)
userNutritionData?.let {
Timber.tag(TAG).d("loadBilledMode${GsonUtils.toJson(it)}")
// userNutritionData?.let {
// Timber.tag(TAG).d("loadBilledMode${GsonUtils.toJson(it)}")
// }
currentFood?.let {
val specPrice = it.specPrice?:0.0
val vipPrice = it.vipPrice?:0.0
binding.tvNormalPrice.text = "${specPrice.format2String(2)} 元/份"
binding.tvVipPrice.text = "${vipPrice.format2String(2)} 元/份"
var calorie = getIntNutritionValue(it.calorie)
calorie = max(calorie, 0)
val fat = getIntNutritionValue(it.fat)
val protein = getIntNutritionValue(it.protein)
val carbohydrate = getIntNutritionValue(it.carbohydrate)
val fatRate = getNutritionRate(fat, calorie)
val proteinRate = getNutritionRate(protein, calorie)
val carbohydrateRate = getNutritionRate(carbohydrate, calorie)
binding.calorieInclude.run {
tvCalorie.text = "$calorie"
tvFatRate.text = "$fatRate%"
tvProteinRate.text = "$proteinRate%"
tvCarbohydrateRate.text = "$carbohydrateRate%"
viewFatLine.updateLayoutParams { height = (fatRate/100.0*84).roundToInt()*1.dp }
viewProteinLine.updateLayoutParams { height = (proteinRate/100.0*84).roundToInt()*1.dp }
viewCarbohydrateLine.updateLayoutParams { height = (carbohydrateRate/100.0*84).roundToInt()*1.dp }
}
}
}
private fun getNutritionRate(value: Int, total: Int): Int{
if (value == 0 || total == 0) return 0
return (100.0 * value / total).roundToInt()
}
private fun getIntNutritionValue(text: String?): Int {
return if (text.isNullOrBlank()) 0 else text.toFloat().roundToInt() }
/**
* 餐品识别成功,不计费模式
*/
@@ -296,7 +344,8 @@ class MainScreenPresentation(
//updateFoodInfo(foodInfo)
userNutritionData?.let {
binding.nutritionInclude.tvUserName.text = it.userName.maskName()
binding.nutritionInclude.tvRecommendHeat.text = "推荐热量:${it.recommendMin}-${it.recommendMax}kcal"
binding.nutritionInclude.tvRecommendHeat.text =
"推荐热量:${it.recommendMin}-${it.recommendMax}kcal"
updateWeight(lastWeight / 1000)
}
}
@@ -307,7 +356,7 @@ class MainScreenPresentation(
fun step1FoodRecognizing() {
hideStandbyScreen()
activity.resetTouchTime()
activity.resumeAnalysis()
Timber.tag(TAG).d("step1")
//if (abs(lastWeight.toInt()) <= 5) {
// activity.runOnUiThread {
@@ -332,8 +381,8 @@ class MainScreenPresentation(
binding.tvFoodName.text = "餐品识别中..."
binding.tvFoodRecPrompt.visible()
binding.flCameraView.visible()
binding.ivRecImage.gone()
binding.ivPreviewImage.visible()
//binding.ivRecImage.gone()
binding.ivFaceRecMask.gone()
binding.tvFaceTip.gone()
binding.llPriceInfo.gone()
@@ -344,17 +393,21 @@ class MainScreenPresentation(
activity.clearFoodList()
}
fun foodRecSuccess(foodInfo: FoodInfo) {
//识别逻辑完成根据是否计费显示不同页面
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
if (mode == 0) {
//计费
loadBilledMode()
} else {
//不计费
loadUnbilledMode()
}
}
// fun foodRecSuccess(foodInfo: FoodInfo) {
// //识别逻辑完成根据是否计费显示不同页面
// val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
// if (mode == 0) {
// //计费
// loadBilledMode()
// } else {
// //不计费
// //userViewModel.getUserNutritionData(
// // userId = userId,
// // foodId = currentFood!!.foodId!!
// //)
// loadUnbilledMode()
// }
// }
/**
* 用户人脸识别中
@@ -377,7 +430,7 @@ class MainScreenPresentation(
binding.tvFoodRecPrompt.visible()
binding.llPriceInfo.gone()
//binding.ivRecImage.gone()
binding.ivRecImage.gone()
binding.ivPreviewImage.gone()
dinnerTypeInfo = null
@@ -386,7 +439,9 @@ class MainScreenPresentation(
stepChangeCallback(currentStep)
currentFood = foodInfo
userViewModel.getDinnerType()
resumeCamera()
}
@@ -395,18 +450,37 @@ class MainScreenPresentation(
fun updateFood(foodInfo: FoodInfo?) {
Timber.tag(TAG).d("updateFood")
currentFood = foodInfo
if (foodInfo != null) {
if (foodInfo == null) {
return
}
binding.tvFoodName.text = foodInfo.foodName
binding.ivPreviewImage.gone()
binding.ivRecImage.let {
it.visible()
val imageUrl = if (foodInfo.foodImg.isNullOrBlank()) foodInfo.photoUri else foodInfo.foodImg
it.load(imageUrl)
}
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
if (mode == 0) {
//计费,查询营养信息、价格信息------------------------
loadBilledMode()
} else {
//不计费
//开启人脸识别
if (currentStep == 1) {
step2FaceRecognizing(foodInfo)
} else {
updateFoodInfo(foodInfo)
}
}
//if (currentStep == 1) {
// step2FaceRecognizing(foodInfo)
//} else {
// updateFoodInfo(foodInfo)
//}
}
private fun updateFoodInfo(foodInfo: FoodInfo) {
binding.tvFoodName.text = foodInfo.foodName
binding.ivPreviewImage.gone()
// binding.tvFoodName.text = foodInfo.foodName
// binding.ivPreviewImage.gone()
//binding.ivRecImage.visible()
// if (foodInfo.photoUri != null) {
// GlideUtils.loadRoundCornerImage(
@@ -429,9 +503,11 @@ class MainScreenPresentation(
var weight = weight1
if (weight < 0) weight = 0.0
debouncer.debounce {
Timber.tag(TAG).d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight")
Timber.tag(TAG)
.d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight")
val dinnerType = dinnerTypeInfo!!.dinnerType!!
Timber.tag(TAG).d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}")
Timber.tag(TAG)
.d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}")
val calcResultInfo = UserNutritionUtils.calculateNutrition(
currentFood!!,
userNutritionData!!,
@@ -528,6 +604,7 @@ class MainScreenPresentation(
}
}
}
fun updateImage(bitmap: Bitmap) {
activity.runOnUiThread {
binding.ivPreviewImage.setImageBitmap(bitmap)
@@ -538,10 +615,11 @@ class MainScreenPresentation(
* 余量取餐
*/
fun updateMealPickupMode(mode: Int) {
Timber.tag(TAG).d("updateMealPickupMode mode = $mode")
mealPickupMode = mode
step1FoodRecognizing()
Timber.tag(TAG).d("updateMealPickupMode mode = $mode")
mealPickupMode = mode
step1FoodRecognizing()
}
override fun onStop() {
if (rgbCameraHelper != null) {
rgbCameraHelper!!.release()
@@ -605,7 +683,8 @@ class MainScreenPresentation(
recognizeViewModel.recognizeConfiguration
.observe(activity, Observer { recognizeConfiguration: RecognizeConfiguration? ->
Timber.tag(TAG).i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
Timber.tag(TAG)
.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
})
recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? ->
Timber.tag(TAG).i("recognizeNotice observe notice = $notice")
@@ -614,26 +693,34 @@ class MainScreenPresentation(
recognizeViewModel.recognizeUserId.observe(
activity,
Observer { compareResult: CompareResult ->
Timber.tag(TAG).i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}")
Timber.tag(TAG)
.i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}")
recognitionTime = System.currentTimeMillis()
recognitionWeight = lastWeight
lastFaceTrackId = compareResult.trackId
val faceEntity = compareResult.faceEntity
val userId = faceEntity.userName
if (userId == null ) return@Observer
if (userId == null) return@Observer
if (currentFood == null) {
//重新识别
activity.runOnUiThread {
ToastUtils.showToast("currentFood == null")
}
//activity.recognizeFood()
//step1FoodRecognizing()
return@Observer
currentFood = activity.checkedItem
}
userViewModel.getUserNutritionData(
userId = userId,
foodId = currentFood!!.foodId!!
)
if (currentFood == null) {
activity.runOnUiThread {
ToastUtils.showToast("请选择菜品")
return@runOnUiThread
}
}
// TODO: ------------------人脸识别成功
//-------------------------------------------------
// TODO: ------------------人脸识别成功
step3ShowRecognizeResult()
//根据接口数据更新热量数据--------------------------
loadUnbilledMode()
// userViewModel.getUserNutritionData(
// userId = userId,
// foodId = currentFood!!.foodId!!
// )
})
recognizeViewModel.drawRectInfoText.observe(activity, Observer { info ->
@@ -724,7 +811,8 @@ class MainScreenPresentation(
displayOrientation: Int,
isMirror: Boolean
) {
Timber.tag(TAG).d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
Timber.tag(TAG)
.d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
activity.runOnUiThread({
val previewSizeRgb = camera.getParameters().getPreviewSize()
val layoutParams = adjustPreviewViewSize(
@@ -733,8 +821,10 @@ class MainScreenPresentation(
previewSizeRgb, displayOrientation, 0.6F
)
Timber.tag(TAG).d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}")
Timber.tag(TAG).d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}")
Timber.tag(TAG)
.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}")
Timber.tag(TAG)
.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}")
Timber.tag(TAG).d(
"initRgbCamera isMirror = ${isMirror}, isDrawRgbRectHorizontalMirror = ${
ConfigUtil.isDrawRgbRectHorizontalMirror(
@@ -790,16 +880,19 @@ class MainScreenPresentation(
}
override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) {
Timber.tag(TAG).i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}")
Timber.tag(TAG)
.i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}")
if (rgbFaceRectTransformer != null) {
rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation
}
Timber.tag(TAG).i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation")
Timber.tag(TAG)
.i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation")
}
}
val measuredWidth = binding.dualCameraTexturePreviewRgb.measuredWidth
val measuredHeight = binding.dualCameraTexturePreviewRgb.measuredHeight
Timber.tag(TAG).i("initRgbCamera measuredWidth=$measuredWidthmeasuredHeight=$measuredHeight")
val measuredHeight = binding.dualCameraTexturePreviewRgb.measuredHeight
Timber.tag(TAG)
.i("initRgbCamera measuredWidth=$measuredWidthmeasuredHeight=$measuredHeight")
val previewConfig: PreviewConfig = recognizeViewModel.previewConfig
rgbCameraHelper = DualCameraHelper.Builder()
@@ -831,7 +924,8 @@ class MainScreenPresentation(
displayOrientation: Int,
isMirror: Boolean
) {
Timber.tag(TAG).d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
Timber.tag(TAG)
.d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
val previewSizeIr = camera.getParameters().getPreviewSize()
val layoutParams = adjustPreviewViewSize(
binding.dualCameraTexturePreviewRgb,
@@ -872,7 +966,8 @@ class MainScreenPresentation(
if (irFaceRectTransformer != null) {
irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation
}
Timber.tag(TAG).i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation")
Timber.tag(TAG)
.i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation")
}
}
@@ -916,14 +1011,17 @@ class MainScreenPresentation(
// 识别成功
binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList)
}
if (facePreviewInfoList.isEmpty() || (lastFaceTrackId != facePreviewInfoList[0]!!.trackId)) {
val listIsEmpty = facePreviewInfoList.isEmpty()
val listFirstTrackId = if (listIsEmpty.not()) facePreviewInfoList[0]!!.trackId else null
Timber.tag(TAG).d("listIsEmpty=$listIsEmpty,lastFaceTrackId=$lastFaceTrackId,listFirstTrackId=$listFirstTrackId")
if (listIsEmpty || (lastFaceTrackId != listFirstTrackId)) {
if (lastFaceTrackId != -1) {
mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
Timber.tag(TAG).i("$lastFaceTrackId 用户离开")
lastFaceTrackId = -1
postUserData()
if (mealPickupMode == 0) {
activity.isAnalyzing = false
step1FoodRecognizing()
} else {
step2FaceRecognizing(currentFood!!)
@@ -935,7 +1033,8 @@ class MainScreenPresentation(
fun postUserData() {
Timber.tag(TAG).d("postUserData")
if (userNutritionData == null || currentFood == null) {
Timber.tag(TAG).d("postUserData userNutritionData = ${userNutritionData == null}, currentFood = ${currentFood == null}")
Timber.tag(TAG)
.d("postUserData userNutritionData = ${userNutritionData == null}, currentFood = ${currentFood == null}")
return
}
var eatWeight = 0.0
@@ -947,7 +1046,7 @@ class MainScreenPresentation(
}
val userNutritionParam = UserNutritionParam(
userId = userNutritionData?.userId!!,
foodId = currentFood?.foodId !!,
foodId = currentFood?.foodId!!,
faceTime = recognitionTime,
faceEndTime = System.currentTimeMillis(),
eatWeight = eatWeight,//lastWeight