diff --git a/app/build.gradle.kts b/app/build.gradle.kts index eab1e91..760c9ae 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -59,7 +59,7 @@ android { } dependencies { - implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar", "*.jar")))) + //implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar", "*.jar")))) implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) implementation(libs.material) @@ -110,17 +110,19 @@ dependencies { implementation(libs.pytorch.android) implementation(libs.pytorch.android.torchvision) - implementation("io.github.scwang90:refresh-layout-kernel:3.0.0-alpha") - implementation("io.github.scwang90:refresh-header-classics:3.0.0-alpha") + implementation(libs.baseRecyclerViewAdapterHelper4) + + implementation(libs.refresh.layout.kernel) + implementation(libs.refresh.header.classics) val objectboxVersion = "5.0.1" - debugImplementation("io.objectbox:objectbox-android-objectbrowser:$objectboxVersion") + debugImplementation(libs.objectbox.android.objectbrowser) // releaseImplementation("io.objectbox:objectbox-android:$objectboxVersion") // implementation("io.objectbox:objectbox-fulltext:5.0.1") implementation(libs.androidx.recyclerview) - implementation("org.greenrobot:eventbus:3.2.0") + implementation(libs.eventbus) } apply(plugin = "io.objectbox") \ No newline at end of file diff --git a/app/libs/BaseRecyclerViewAdapterHelper4-4.1.2.aar b/app/libs/BaseRecyclerViewAdapterHelper4-4.1.2.aar deleted file mode 100644 index e493c3c..0000000 Binary files a/app/libs/BaseRecyclerViewAdapterHelper4-4.1.2.aar and /dev/null differ diff --git a/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt index 627a702..ebd5b07 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt @@ -32,10 +32,10 @@ import com.sw.dualscreen.databinding.ActivityMainBinding import com.sw.dualscreen.dialog.RemindDialog import com.sw.dualscreen.ext.dp import com.sw.dualscreen.ext.gone +import com.sw.dualscreen.ext.invisible import com.sw.dualscreen.ext.load import com.sw.dualscreen.ext.visible import com.sw.dualscreen.model.response.ChargeModeEvent -import com.sw.dualscreen.model.response.ClickBackEvent import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.FoodOrder import com.sw.dualscreen.model.response.PaySuccessEvent @@ -79,7 +79,6 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import java.util.Locale import java.util.concurrent.Executors -import kotlin.math.abs import kotlin.math.roundToInt /** @@ -91,6 +90,9 @@ class MainActivity : BaseActivity() { companion object { private const val TAG = "MainActivity" const val TIME_OUT = 5 * 60 * 1000L + + const val WEIGHT_CHANGE_VALUE = 25 + const val WEIGHT_RESET_RECOGNIZE = 10 } private val viewModel by viewModels() @@ -101,28 +103,36 @@ class MainActivity : BaseActivity() { private var presentation: MainScreenPresentation? = null private val executor = Executors.newSingleThreadExecutor() private val handler by lazy { Handler(Looper.getMainLooper()) } - private val searchFoodList = mutableListOf() private val adapter by lazy { - MainFoodListAdapter(searchFoodList).apply { + MainFoodListAdapter(mutableListOf()).apply { setOnItemClickListener { adapter, view, position -> - if (searchFoodList[position].isChecked) { + if (items[position].isChecked) { return@setOnItemClickListener } - searchFoodList.forEachIndexed { index, info -> - searchFoodList[index].isChecked = index == position + items.forEachIndexed { index, info -> + items[index].isChecked = index == position } - val item = searchFoodList[position] + val item = items[position] log("itemClick ${item.foodName}, position = $position") item.photoUri = null checkedItem = item notifyDataSetChanged() updateCurrentFood(item) - //0-计费,1-不计费 - val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) - //不计费模式切换菜品,重新加载数据 - if (mode == 1) { - presentation?.isAgainLoadData = false - presentation?.loadUnbilledMode() + if (settlementMode == 0) { + //联合支付,切换菜品重新请求接口 + presentation?.let { + it.pauseCamera() + it.step2FaceRecognizing(item, true) + } +// presentation?.step3ShowRecognizeResult(presentation!!.currentUserId?:"") + } else { + //0-计费,1-不计费 + val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) + //不计费模式切换菜品,重新加载数据 + if (mode == 1) { + presentation?.isAgainLoadData = false + presentation?.loadUnbilledMode() + } } } } @@ -132,7 +142,7 @@ class MainActivity : BaseActivity() { private var cameraProviderFuture: ListenableFuture? = null private var canIdentify: Boolean = false private var bottomSheetDialog: CustomBottomSheetDialog? = null - private var lastWeight: Double = 0.0 + private var lastWeight: Int = 0 private var lastPhotoUri: Uri? = null // 最后拍照的图片 private var debouncer = Debouncer(5000) private var isRecognitionFood = true @@ -200,8 +210,8 @@ class MainActivity : BaseActivity() { checkedItem = it it.photoUri = null updateCurrentFood(it) - searchFoodList.forEachIndexed { index, info -> - searchFoodList[index].isChecked = false + adapter.items.forEachIndexed { index, info -> + adapter.items[index].isChecked = false } adapter.notifyDataSetChanged() } @@ -209,7 +219,7 @@ class MainActivity : BaseActivity() { } binding.recyclerview.let { - it.layoutManager = GridLayoutManager(this, 2) + it.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false) it.adapter = adapter } binding.tvFoodName.setOnClickListener { @@ -220,7 +230,7 @@ class MainActivity : BaseActivity() { } } - private var recognizeWeight = 0.0 + private var recognizeWeight = 0 fun updateCurrentFood(foodInfo: FoodInfo?) { if (foodInfo == null) { binding.tvFoodName.text = "-" @@ -245,52 +255,75 @@ class MainActivity : BaseActivity() { binding.ivImg.load(imgUrl) } - override fun registerDataChange() { - super.registerDataChange() - SensorScaleUtils.addWeightListener { weight -> - log("registerDataChange weight = $weight") - //runOnUiThread { binding.tvShowWeight.text="${weight*1000}克" } - if (presentation?.jointPaymentQueryFinish == true) { - //0-即放即取,1-余量计量 - val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 - if (mealPickupMode == 0 && weight <= 0.005) { - isAnalyzing = false - presentation?.step1FoodRecognizing() - } else { - return@addWeightListener - } + private fun readWeight(weight: Int) { + log("registerDataChange weight = $weight") + //runOnUiThread { binding.tvShowWeight.text="${weight*1000}克" } + if (settlementMode == 0) { + //联合支付------------------------------------------- + //0-即放即取,1-余量计量 + val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 + if (mealPickupMode == 1) { + return } - - //if (presentation?.currentFood == null) return@addWeightListener - if (lastWeight - weight > 0.005) { - //及放及取,从秤上拿走超过5克 - if (presentation?.mealPickupMode == 0) { - presentation?.updateWeight(weight) - lastWeight = weight - return@addWeightListener + //即放即取+联合支付人脸查询订单完成 + if (presentation!!.jointPaymentQueryFinish) { + if (weight > WEIGHT_RESET_RECOGNIZE) { + //已识别完成人脸并查询到订单数据,增加重量不再重新识别 + return } + //重量小于等于5克时改为识别中页面 + isAnalyzing = false + presentation?.step1FoodRecognizing() + return } - if (isPageVisible.not() || isStartRecognize.not()) { - if (ActivityManager.currentActivity() is MainActivity) { - isPageVisible = true - isStartRecognize = true - } - return@addWeightListener + if (weight <= WEIGHT_RESET_RECOGNIZE) { + //秤上重量过下,显示识别中页面 + presentation?.step1FoodRecognizing() + return } - //0.05 // val isWeightChange = abs(weight - lastWeight) > 0.02 - val isWeightChange = weight - lastWeight > 0.02 + val isWeightChange = weight - lastWeight > WEIGHT_CHANGE_VALUE if (weight != lastWeight) { log("recognizeByWeight---00001,weight=$weight,lastWeight=$lastWeight,isWeightChange=$isWeightChange") } recognizeByWeight(weight, isWeightChange) + return + } + //独立支付------------------------------------------- + if (lastWeight - weight > 5) { + //及放及取,从秤上拿走超过5克 + if (presentation?.mealPickupMode == 0) { + presentation?.updateWeight(weight) + lastWeight = weight + return + } + } + if (isPageVisible.not() || isStartRecognize.not()) { + if (ActivityManager.currentActivity() is MainActivity) { + isPageVisible = true + isStartRecognize = true + } + return + } +// val isWeightChange = abs(weight - lastWeight) > 0.02 + val isWeightChange = weight - lastWeight > WEIGHT_CHANGE_VALUE + if (weight != lastWeight) { + log("recognizeByWeight---00001,weight=$weight,lastWeight=$lastWeight,isWeightChange=$isWeightChange") + } + recognizeByWeight(weight, isWeightChange) + } + + override fun registerDataChange() { + super.registerDataChange() + SensorScaleUtils.addWeightListener { value -> + readWeight(value) } } - private fun recognizeByWeight(weight: Double, isWeightChange: Boolean, block: () -> Unit = {}) { + private fun recognizeByWeight(weight: Int, isWeightChange: Boolean, block: () -> Unit = {}) { presentation?.updateWeight(weight) - if (weight <= 0.005) { + if (weight <= WEIGHT_RESET_RECOGNIZE) { log("recognizeByWeight---00002,秤重未超过5克") //检测到秤上没有东西,重新启动识别菜品 && presentation?.mealPickupMode == 1 isRecognitionFood = true @@ -374,9 +407,10 @@ class MainActivity : BaseActivity() { // e.printStackTrace() // list // } - searchFoodList.clear() - searchFoodList.addAll(list) - adapter.notifyDataSetChanged() + + + adapter.submitList(list) + binding.recyclerview.visible() checkedItem = list[0].also { it.photoUri = lastPhotoUri @@ -559,10 +593,14 @@ class MainActivity : BaseActivity() { } @SuppressLint("NotifyDataSetChanged") - fun clearFoodList() { - //adapter.updateData(listOf()) - searchFoodList.clear() - adapter.notifyDataSetChanged() + fun clearRecognizeFood() { + log("clearRecognizeFood") + binding.recyclerview.invisible() + adapter.submitList(null) + binding.tvToSearch.gone() + + binding.previewView.visible() + binding.ivImg.gone() } private fun updateDateTime() { @@ -594,7 +632,7 @@ class MainActivity : BaseActivity() { log("onResume-00001,isRefreshPage=$isRefreshPage") if (presentation == null || !presentation!!.isShowing) { log("onResume-00002,副屏未显示,加载副屏") - lastWeight = 0.0 + lastWeight = 0 setupSecondaryDisplay() presentation?.step1FoodRecognizing() } else { @@ -603,7 +641,7 @@ class MainActivity : BaseActivity() { isRefreshPage = false //已显示副屏,则进行更新 val weight = lastWeight - lastWeight = 0.0 + lastWeight = 0 presentation?.hideRecImage() presentation?.step1FoodRecognizing() @@ -662,7 +700,7 @@ class MainActivity : BaseActivity() { eatWeight: Int, eatNum: Int, userId: String?, - isMember:Boolean, + isMember: Boolean, notEnoughOneBlock: () -> Unit = {}, successBlock: () -> Unit ) { @@ -800,36 +838,36 @@ class MainActivity : BaseActivity() { val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 //0-计费,1-不计费 val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) ?: 0 - var foodWeight = 0.0 - var eatWeight = 0.0 + var foodWeight = 0 + var eatWeight = 0 if (chargeMode == 0) { //计费 if (mealPickupMode == 0) { //即放即取 - eatWeight = lastWeight * 1000 - foodWeight = lastWeight * 1000 + eatWeight = lastWeight + foodWeight = lastWeight } else { //余量计量 - eatWeight = (recognizeWeight - lastWeight) * 1000 - foodWeight = recognizeWeight * 1000 + eatWeight = recognizeWeight - lastWeight + foodWeight = recognizeWeight log("eatWeight=$eatWeight, recognizeWeight=$recognizeWeight, lastWeight=$lastWeight") } } else { //不计费 - foodWeight = recognizeWeight * 1000 + foodWeight = recognizeWeight eatWeight = if (mealPickupMode == 0) { //即放即取 - recognizeWeight * 1000 + recognizeWeight } else { //余量计量 - (recognizeWeight - lastWeight) * 1000 + recognizeWeight - lastWeight } } - val eatNum = getEatNum(eatWeight, checkedItem!!.specWeight) + val eatNum = getEatNum(eatWeight.toDouble(), checkedItem!!.specWeight) createOrder( foodInfo = checkedItem!!, - foodWeight = foodWeight.roundToInt(), - eatWeight = eatWeight.roundToInt(), + foodWeight = foodWeight, + eatWeight = eatWeight, eatNum = eatNum, userId = null, isMember = false @@ -956,7 +994,8 @@ class MainActivity : BaseActivity() { // private val dealyMillis = 10 * 60 * 1000L private val initialDelay = 10 * 1000L private val dealyMillis = 5 * 1000L -// private var taskPageNo = 1 + + // private var taskPageNo = 1 fun startFaceTask() { faceTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(initialDelay, dealyMillis) { @@ -1097,13 +1136,6 @@ class MainActivity : BaseActivity() { } } - /** - * 隐藏搜索按钮 - */ - fun hideSearchView() { - binding.tvToSearch.gone() - } - // @Subscribe(threadMode = ThreadMode.MAIN) // public fun onResetBox(event: ResetBoxEvent) { // ObjectBox.boxStore.close() diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/BusinessFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/BusinessFragment.kt index fe8bc1f..5624efb 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/BusinessFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/BusinessFragment.kt @@ -77,8 +77,8 @@ class BusinessFragment: BaseFragment() { } } SensorScaleUtils.addWeightListener { value -> - val realWeight = (value * 1000).roundToInt() - binding.tvFoodWeight.text = "$realWeight" + //val realWeight = (value * 1000).roundToInt() + binding.tvFoodWeight.text = "$value" } } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/adapter/FoodOrderAdapter.kt b/app/src/main/java/com/sw/dualscreen/adapter/FoodOrderAdapter.kt index b981004..755a580 100644 --- a/app/src/main/java/com/sw/dualscreen/adapter/FoodOrderAdapter.kt +++ b/app/src/main/java/com/sw/dualscreen/adapter/FoodOrderAdapter.kt @@ -10,19 +10,21 @@ import androidx.core.view.updateLayoutParams import androidx.recyclerview.widget.RecyclerView import com.chad.library.adapter4.BaseQuickAdapter import com.chad.library.adapter4.viewholder.QuickViewHolder -import com.sw.dualscreen.databinding.LayoutFoodListHeaderBinding +import com.sw.dualscreen.databinding.ListItemFoodOrderBinding import com.sw.dualscreen.ext.dp import com.sw.dualscreen.ext.format2String +import com.sw.dualscreen.ext.gone +import com.sw.dualscreen.ext.visible import com.sw.dualscreen.model.response.FoodItem class FoodOrderAdapter(var list: MutableList) : BaseQuickAdapter(list) { - inner class VH(var binding: LayoutFoodListHeaderBinding) : QuickViewHolder(binding.root) + inner class VH(var binding: ListItemFoodOrderBinding) : QuickViewHolder(binding.root) override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { val inflater = LayoutInflater.from(context) - val binding = LayoutFoodListHeaderBinding.inflate(inflater, parent, false) + val binding = ListItemFoodOrderBinding.inflate(inflater, parent, false) return VH(binding) } @@ -31,9 +33,20 @@ class FoodOrderAdapter(var list: MutableList) : val binding = holder.binding item?.let { binding.tvFoodName.text = it.foodName - binding.tvPriceNorm.text = it.foodPrice.format2String(2) + val foodPrice = it.foodPrice.format2String(2) + if (it.orderFrom == 2) { + binding.tvPriceNorm.text = "${it.specName}-${it.specWeight}克" + } else { + binding.tvPriceNorm.text = "${foodPrice}/${it.num}克" + } + //if (it.specName.isNullOrBlank().not()) { + // binding.tvPriceFlag.text = "[${it.specName}]" + //} binding.tvWeight.text = "${it.num}克" binding.tvAmount.text = it.price.format2String(2) + binding.tvLabel.run { + if (it.orderFrom == 2) visible() else gone() + } } setTextColor(binding.tvFoodName, binding.tvPriceNorm, binding.tvWeight, binding.tvAmount) binding.root.updateLayoutParams { diff --git a/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt b/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt index d7ce489..bcb61a7 100644 --- a/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt +++ b/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt @@ -177,7 +177,10 @@ data class FoodItem( val discount: Double = 0.0, val income: Double = 0.0, val foodDifferenceId: Long = 0, - val createTime: String? = null + val createTime: String? = null, + val specName: String? = null, + val specWeight: Int = 0, + val orderFrom: Int = 0 ) data class FoodOrderModel( diff --git a/app/src/main/java/com/sw/dualscreen/presentation/MainScreenPresentation.kt b/app/src/main/java/com/sw/dualscreen/presentation/MainScreenPresentation.kt index bd16bae..743ef23 100644 --- a/app/src/main/java/com/sw/dualscreen/presentation/MainScreenPresentation.kt +++ b/app/src/main/java/com/sw/dualscreen/presentation/MainScreenPresentation.kt @@ -5,24 +5,16 @@ import android.annotation.SuppressLint import android.app.Presentation import android.content.pm.PackageManager import android.graphics.Bitmap -import android.graphics.Outline import android.graphics.Point import android.hardware.Camera -import android.os.Build import android.os.Bundle -import android.text.TextUtils -import android.util.DisplayMetrics import android.view.Display import android.view.View import android.view.ViewGroup -import android.view.ViewOutlineProvider import android.view.ViewTreeObserver import android.widget.FrameLayout -import androidx.annotation.RequiresApi import androidx.core.content.ContextCompat -import androidx.core.view.isInvisible import androidx.core.view.isVisible -import androidx.core.view.postDelayed import androidx.core.view.updateLayoutParams import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope @@ -30,7 +22,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.arcsoft.face.ErrorInfo import com.sw.dualscreen.BuildConfig import com.sw.dualscreen.GlobalKey -import com.sw.dualscreen.MyApp import com.sw.dualscreen.R import com.sw.dualscreen.activity.MainActivity import com.sw.dualscreen.adapter.FoodOrderAdapter @@ -40,7 +31,6 @@ 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.roundedDecimalPlace import com.sw.dualscreen.ext.screenSize import com.sw.dualscreen.ext.visible import com.sw.dualscreen.model.response.DinnerType @@ -66,7 +56,6 @@ import com.sw.plate.utils.arcface.face.model.CompareResult import com.sw.plate.utils.arcface.face.model.FacePreviewInfo import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel -import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel.REGISTER_STATUS_READY import kotlinx.coroutines.flow.drop import kotlinx.coroutines.launch import timber.log.Timber @@ -105,14 +94,14 @@ class MainScreenPresentation( private var irFaceRectTransformer: FaceRectTransformer? = null private var detectWeight = 0.0 //识别菜品时的重量 - var lastWeight = 0.0 // 上一次的计算热量结果 + var lastWeight = 0 // 上一次的计算热量结果 // private var userNutritionData: UserNutritionData? = null private var userNutrition: UserNutrition? = null private var dinnerTypeInfo: DinnerType? = null private val debouncer = Debouncer(500) private var recognitionTime: Long = 0L // 人脸识别时的时间 - var recognitionWeight: Double = 0.0 // 人脸识别时的重量 + var recognitionWeight: Int = 0 // 人脸识别时的重量 private var lastFaceTrackId: Int = -1 // 上一次的人脸信息 var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐 @@ -144,8 +133,8 @@ class MainScreenPresentation( private var isFirstGetWeight = true - fun updateWeight(weight: Double) { - lastWeight = weight * 1000 // 将千克转成克 + fun updateWeight(weight: Int) { + lastWeight = weight Timber.tag(TAG) .d("updateWeight lastWeight = $weight, currentStep = $currentStep, isGoStep1 = $isGoStep1") //0-即放即取,1-余量计量 @@ -164,14 +153,14 @@ class MainScreenPresentation( // } // isFirstGetWeight = true // } - if (currentStep == 2 && lastWeight <= 5 && isGoStep1) { + if (currentStep == 2 && lastWeight <= MainActivity.WEIGHT_RESET_RECOGNIZE && isGoStep1) { //人脸识别过程中,秤上物品拿走 isGoStep1 = false activity.runOnUiThread { Timber.tag(TAG).e("切回step1") step1FoodRecognizing() } - } else if (lastWeight <= 5) { + } else if (lastWeight <= MainActivity.WEIGHT_RESET_RECOGNIZE) { isGoStep1 = false activity.runOnUiThread { Timber.tag(TAG).e("切回step1") @@ -287,6 +276,14 @@ class MainScreenPresentation( } } + private fun setTopInfoVisible() { + binding.llTopInfo.visible() + binding.flFoodDetail.gone() + binding.llTopInfo.updateLayoutParams { + height = activity.screenSize[1] / 2 + 120.dp + } + } + /** * 显示识别出的菜品信息 */ @@ -297,8 +294,7 @@ class MainScreenPresentation( currentStep = 3 stepChangeCallback(currentStep) - binding.llTopInfo.visible() - binding.flFoodDetail.gone() + setTopInfoVisible() //根据接口数据更新热量数据-------------------------- userViewModel.getUserNutritionData(userId = userId) { nutrition -> activity.runOnUiThread { @@ -491,6 +487,9 @@ class MainScreenPresentation( * 餐品识别中 */ fun step1FoodRecognizing() { + if (currentStep == 1) { + return + } Timber.tag(TAG).d("main,step1,耗时:${System.currentTimeMillis() - startTime}") startTime = System.currentTimeMillis() jointPaymentQueryFinish = false @@ -505,7 +504,6 @@ class MainScreenPresentation( // } // return //} - currentStep = 1 LightManager.closeGreenLight() LightManager.closeRedLight() @@ -513,12 +511,9 @@ class MainScreenPresentation( currentFood = null // userNutritionData = null userNutrition = null - recognitionWeight = 0.0 + recognitionWeight = 0 - stepChangeCallback(currentStep) - - binding.llTopInfo.visible() - binding.flFoodDetail.gone() + setTopInfoVisible() binding.calorieInclude.root.gone() binding.nutritionInclude.root.gone() @@ -537,8 +532,10 @@ class MainScreenPresentation( binding.flRecognizeIr.gone() pauseCamera() - activity.clearFoodList() - activity.hideSearchView() + activity.clearRecognizeFood() + + currentStep = 1 + stepChangeCallback(currentStep) } // fun foodRecSuccess(foodInfo: FoodInfo) { @@ -560,9 +557,14 @@ class MainScreenPresentation( /** * 用户人脸识别中 */ - fun step2FaceRecognizing(foodInfo: FoodInfo) { + fun step2FaceRecognizing(foodInfo: FoodInfo, hideFoodDetail: Boolean = false) { isGoStep1 = true Timber.tag(TAG).d("main,step2,耗时:${System.currentTimeMillis() - startTime}") + + if (hideFoodDetail) { + setTopInfoVisible() + } + startTime = System.currentTimeMillis() currentStep = 2 LightManager.closeRedLight() @@ -586,7 +588,7 @@ class MainScreenPresentation( dinnerTypeInfo = null // userNutritionData = null userNutrition = null - recognitionWeight = 0.0 + recognitionWeight = 0 stepChangeCallback(currentStep) currentFood = foodInfo @@ -668,12 +670,12 @@ class MainScreenPresentation( // } } - private fun calculateNutrition(weight1: Double) { + private fun calculateNutrition(value: Int) { if (currentFood == null || userNutrition == null) { return } - var weight = weight1 - if (weight < 0) weight = 0.0 + var weight = value + if (weight < 0) weight = 0 debouncer.debounce { Timber.tag(TAG) .d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight") @@ -684,7 +686,7 @@ class MainScreenPresentation( currentFood!!, // userNutritionData!!, userNutrition!!, - weight, + weight.toDouble(), dinnerType = dinnerType ?: "" ) // Timber.tag(TAG).d("calculateNutrition calcResultInfo = $calcResultInfo") @@ -830,8 +832,23 @@ class MainScreenPresentation( isRecognition = false recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) + //triggerReidentify() + } + /** + * 重置人脸跟踪状态,让已在画面中的人脸重新触发识别 + * 适用场景:切换按钮后需要重新识别当前画面中的人脸 + */ + fun triggerReidentify() { + // 清除UI上的人脸框 + binding.dualCameraFaceRectView.clearFaceInfo() + // 清除本地跟踪数据 + clearLeftFaceData() + // 重置上一次的 trackId,避免 drawPreviewInfo 中的去重逻辑拦截 + lastFaceTrackId = -1 + // 插入空帧,让引擎重置内部跟踪状态 + // isRecognition 保持 true,相机继续送帧,下一帧真实人脸会产生新 trackId + recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) } - private var recognizeTime = 0L private fun initArcViewModel() { recognizeViewModel.setLiveType(livenessType) @@ -1187,8 +1204,7 @@ class MainScreenPresentation( } createOrder(notEnoughOneBlock = { if (activity.settlementMode == 0) { - binding.flFoodDetail.gone() - binding.llTopInfo.visible() + setTopInfoVisible() } // if (mealPickupMode == 0) { currentStep = 2 @@ -1249,11 +1265,11 @@ class MainScreenPresentation( //userViewModel.postUserNutritionData(listOf(userNutritionParam)) activity.createOrder( foodInfo = currentFood!!, - foodWeight = lastWeight.roundToInt(), - eatWeight = eatWeight.roundToInt(), - eatNum = activity.getEatNum(eatWeight, currentFood!!.specWeight), + foodWeight = lastWeight, + eatWeight = eatWeight, + eatNum = activity.getEatNum(eatWeight.toDouble(), currentFood!!.specWeight), userId = currentUserId, - isMember = isMember , + isMember = isMember, notEnoughOneBlock = notEnoughOneBlock, successBlock = { activity.runOnUiThread { @@ -1316,11 +1332,12 @@ class MainScreenPresentation( binding.flFoodDetail.visible() binding.detailInclude.let { it.root.updateLayoutParams { - height = activity.screenSize[1]/2 + height = activity.screenSize[1] / 2 + 120.dp } it.tvFoodList.run { if (adapter == null) { - layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false) + layoutManager = + LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false) adapter = foodOrderAdapter } } @@ -1332,10 +1349,36 @@ class MainScreenPresentation( } foodOrderAdapter.notifyDataSetChanged() binding.detailInclude.tvTotalWeight.text = "总重量:${model.eatWeightSum}克" - binding.detailInclude.tvTotalCalorie.text = "总热量:${model.calorie.roundToInt()}千卡" + binding.detailInclude.tvTotalCalorie.text = + "总热量:${model.calorie.roundToInt()}千卡" jointPaymentQueryFinish = true } } } + /** + * 构造符合分辨率的 NV21 格式全黑帧 + * @param width 图像宽度(如 1920) + * @param height 图像高度(如 1080) + * @return 合法的全黑帧字节数组 + */ + private fun createBlackNV21Frame(width: Int, height: Int): ByteArray { + val frameSize = width * height + val nv21Data = ByteArray(frameSize * 3 / 2) // NV21 格式长度 = 宽×高×1.5 + + // Y 分量(亮度)设为 0(全黑),UV 分量设为 128(默认值) + // 1. 填充 Y 分量(前 frameSize 个字节) +// Arrays.fill(nv21Data, 0, frameSize, 0.toByte()) + nv21Data.fill(0, 0, frameSize) + // 2. 填充 UV 分量(后 frameSize/2 个字节) +// Arrays.fill(nv21Data, frameSize, nv21Data.size, 128.toByte()) + nv21Data.fill(128.toByte(), frameSize, nv21Data.size) + + return nv21Data + } + + // 调用示例:构造 1920×1080 的全黑帧(长度 1382400) +// private val emptyFrame = createBlackNV21Frame(1920, 1080) + private val emptyFrame = createBlackNV21Frame(1280, 720) + } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt b/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt index a1783e3..cfc52b5 100644 --- a/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt +++ b/app/src/main/java/com/sw/dualscreen/sdk/SensorScaleUtils.kt @@ -7,7 +7,7 @@ import timber.log.Timber import kotlin.math.roundToInt typealias Callback = (Double) -> Unit -typealias WeightCallback = (Double) -> Unit +typealias WeightCallback = (Int) -> Unit private const val TAG = "SensorScaleUtils" @@ -45,7 +45,7 @@ object SensorScaleUtils { } weightCallbackList.forEach { - it.invoke(value) + it.invoke((value * 1000).roundToInt()) } } diff --git a/app/src/main/res/drawable/bg_order_flag.xml b/app/src/main/res/drawable/bg_order_flag.xml new file mode 100644 index 0000000..220e6d3 --- /dev/null +++ b/app/src/main/res/drawable/bg_order_flag.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_user_nutrition_new.xml b/app/src/main/res/layout/item_user_nutrition_new.xml index 6eb5453..2da604e 100644 --- a/app/src/main/res/layout/item_user_nutrition_new.xml +++ b/app/src/main/res/layout/item_user_nutrition_new.xml @@ -285,7 +285,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 92c874c..3b42003 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,6 +2,7 @@ agp = "8.10.1" core = "3.4.1" androidCore = "3.3.0" +eventbus = "3.2.0" glide = "4.16.0" kotlin = "2.0.21" coreKtx = "1.10.1" @@ -14,6 +15,9 @@ activity = "1.8.0" constraintlayout = "2.1.4" accompanistPermissions = "0.37.3" cameraCore = "1.4.1" +objectboxVersion = "5.0.1" +refreshLayoutKernel = "3.0.0-alpha" +refreshHeaderClassics = "3.0.0-alpha" retrofit = "3.0.0" okhttp = "4.12.0" timber = "5.0.1" @@ -30,11 +34,13 @@ pytorch = "1.13.0" recyclerview = "1.3.2" -#baseQuickAdapter = "4.1.2" +baseQuickAdapter = "3.0.4" +baseQuickAdapter4 = "4.1.2" [libraries] android-core = { module = "com.google.zxing:android-core", version.ref = "androidCore" } core = { module = "com.google.zxing:core", version.ref = "core" } +eventbus = { module = "org.greenrobot:eventbus", version.ref = "eventbus" } glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } @@ -56,7 +62,10 @@ hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", ve hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" } logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } +objectbox-android-objectbrowser = { module = "io.objectbox:objectbox-android-objectbrowser", version.ref = "objectboxVersion" } okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } +refresh-header-classics = { module = "io.github.scwang90:refresh-header-classics", version.ref = "refreshHeaderClassics" } +refresh-layout-kernel = { module = "io.github.scwang90:refresh-layout-kernel", version.ref = "refreshLayoutKernel" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } @@ -68,10 +77,12 @@ androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } +#noinspection Aligned16KB pytorch-android = { group = "org.pytorch", name = "pytorch_android", version.ref = "pytorch" } pytorch-android-torchvision = { group = "org.pytorch", name = "pytorch_android_torchvision", version.ref = "pytorch" } -#base-quick-adapter-ktx = { module = "io.github.cymchad:BaseRecyclerViewAdapterHelper4", version.ref = "baseQuickAdapter" } +#baseRecyclerViewAdapterHelper = { module = "com.github.CymChad:BaseRecyclerViewAdapterHelper", version.ref = "baseQuickAdapter" } +baseRecyclerViewAdapterHelper4 = { module = "io.github.cymchad:BaseRecyclerViewAdapterHelper4", version.ref = "baseQuickAdapter4" } androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }