联合支付功能调试

This commit is contained in:
2026-03-23 18:13:55 +08:00
parent bf8444e5d5
commit c4a6101a7b
13 changed files with 350 additions and 143 deletions
+7 -5
View File
@@ -59,7 +59,7 @@ android {
} }
dependencies { 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.core.ktx)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)
implementation(libs.material) implementation(libs.material)
@@ -110,17 +110,19 @@ dependencies {
implementation(libs.pytorch.android) implementation(libs.pytorch.android)
implementation(libs.pytorch.android.torchvision) implementation(libs.pytorch.android.torchvision)
implementation("io.github.scwang90:refresh-layout-kernel:3.0.0-alpha") implementation(libs.baseRecyclerViewAdapterHelper4)
implementation("io.github.scwang90:refresh-header-classics:3.0.0-alpha")
implementation(libs.refresh.layout.kernel)
implementation(libs.refresh.header.classics)
val objectboxVersion = "5.0.1" val objectboxVersion = "5.0.1"
debugImplementation("io.objectbox:objectbox-android-objectbrowser:$objectboxVersion") debugImplementation(libs.objectbox.android.objectbrowser)
// releaseImplementation("io.objectbox:objectbox-android:$objectboxVersion") // releaseImplementation("io.objectbox:objectbox-android:$objectboxVersion")
// implementation("io.objectbox:objectbox-fulltext:5.0.1") // implementation("io.objectbox:objectbox-fulltext:5.0.1")
implementation(libs.androidx.recyclerview) implementation(libs.androidx.recyclerview)
implementation("org.greenrobot:eventbus:3.2.0") implementation(libs.eventbus)
} }
apply(plugin = "io.objectbox") apply(plugin = "io.objectbox")
Binary file not shown.
@@ -32,10 +32,10 @@ import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.dialog.RemindDialog import com.sw.dualscreen.dialog.RemindDialog
import com.sw.dualscreen.ext.dp import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.gone import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.invisible
import com.sw.dualscreen.ext.load import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.visible import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.ChargeModeEvent 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.FoodInfo
import com.sw.dualscreen.model.response.FoodOrder import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.PaySuccessEvent import com.sw.dualscreen.model.response.PaySuccessEvent
@@ -79,7 +79,6 @@ import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.Locale import java.util.Locale
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.roundToInt import kotlin.math.roundToInt
/** /**
@@ -91,6 +90,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
companion object { companion object {
private const val TAG = "MainActivity" private const val TAG = "MainActivity"
const val TIME_OUT = 5 * 60 * 1000L const val TIME_OUT = 5 * 60 * 1000L
const val WEIGHT_CHANGE_VALUE = 25
const val WEIGHT_RESET_RECOGNIZE = 10
} }
private val viewModel by viewModels<UserViewModel>() private val viewModel by viewModels<UserViewModel>()
@@ -101,28 +103,36 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private var presentation: MainScreenPresentation? = null private var presentation: MainScreenPresentation? = null
private val executor = Executors.newSingleThreadExecutor() private val executor = Executors.newSingleThreadExecutor()
private val handler by lazy { Handler(Looper.getMainLooper()) } private val handler by lazy { Handler(Looper.getMainLooper()) }
private val searchFoodList = mutableListOf<FoodInfo>()
private val adapter by lazy { private val adapter by lazy {
MainFoodListAdapter(searchFoodList).apply { MainFoodListAdapter(mutableListOf()).apply {
setOnItemClickListener { adapter, view, position -> setOnItemClickListener { adapter, view, position ->
if (searchFoodList[position].isChecked) { if (items[position].isChecked) {
return@setOnItemClickListener return@setOnItemClickListener
} }
searchFoodList.forEachIndexed { index, info -> items.forEachIndexed { index, info ->
searchFoodList[index].isChecked = index == position items[index].isChecked = index == position
} }
val item = searchFoodList[position] val item = items[position]
log("itemClick ${item.foodName}, position = $position") log("itemClick ${item.foodName}, position = $position")
item.photoUri = null item.photoUri = null
checkedItem = item checkedItem = item
notifyDataSetChanged() notifyDataSetChanged()
updateCurrentFood(item) updateCurrentFood(item)
//0-计费,1-不计费 if (settlementMode == 0) {
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) //联合支付,切换菜品重新请求接口
//不计费模式切换菜品,重新加载数据 presentation?.let {
if (mode == 1) { it.pauseCamera()
presentation?.isAgainLoadData = false it.step2FaceRecognizing(item, true)
presentation?.loadUnbilledMode() }
// 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<ActivityMainBinding>() {
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
private var canIdentify: Boolean = false private var canIdentify: Boolean = false
private var bottomSheetDialog: CustomBottomSheetDialog? = null private var bottomSheetDialog: CustomBottomSheetDialog? = null
private var lastWeight: Double = 0.0 private var lastWeight: Int = 0
private var lastPhotoUri: Uri? = null // 最后拍照的图片 private var lastPhotoUri: Uri? = null // 最后拍照的图片
private var debouncer = Debouncer(5000) private var debouncer = Debouncer(5000)
private var isRecognitionFood = true private var isRecognitionFood = true
@@ -200,8 +210,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
checkedItem = it checkedItem = it
it.photoUri = null it.photoUri = null
updateCurrentFood(it) updateCurrentFood(it)
searchFoodList.forEachIndexed { index, info -> adapter.items.forEachIndexed { index, info ->
searchFoodList[index].isChecked = false adapter.items[index].isChecked = false
} }
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
} }
@@ -209,7 +219,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
binding.recyclerview.let { binding.recyclerview.let {
it.layoutManager = GridLayoutManager(this, 2) it.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false)
it.adapter = adapter it.adapter = adapter
} }
binding.tvFoodName.setOnClickListener { binding.tvFoodName.setOnClickListener {
@@ -220,7 +230,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} }
private var recognizeWeight = 0.0 private var recognizeWeight = 0
fun updateCurrentFood(foodInfo: FoodInfo?) { fun updateCurrentFood(foodInfo: FoodInfo?) {
if (foodInfo == null) { if (foodInfo == null) {
binding.tvFoodName.text = "-" binding.tvFoodName.text = "-"
@@ -245,52 +255,75 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.ivImg.load(imgUrl) binding.ivImg.load(imgUrl)
} }
override fun registerDataChange() { private fun readWeight(weight: Int) {
super.registerDataChange() log("registerDataChange weight = $weight")
SensorScaleUtils.addWeightListener { weight -> //runOnUiThread { binding.tvShowWeight.text="${weight*1000}克" }
log("registerDataChange weight = $weight") if (settlementMode == 0) {
//runOnUiThread { binding.tvShowWeight.text="${weight*1000}克" } //联合支付-------------------------------------------
if (presentation?.jointPaymentQueryFinish == true) { //0-即放即取,1-余量计量
//0-即放即取,1-余量计量 val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 if (mealPickupMode == 1) {
if (mealPickupMode == 0 && weight <= 0.005) { return
isAnalyzing = false
presentation?.step1FoodRecognizing()
} else {
return@addWeightListener
}
} }
//即放即取+联合支付人脸查询订单完成
//if (presentation?.currentFood == null) return@addWeightListener if (presentation!!.jointPaymentQueryFinish) {
if (lastWeight - weight > 0.005) { if (weight > WEIGHT_RESET_RECOGNIZE) {
//及放及取,从秤上拿走超过5克 //已识别完成人脸并查询到订单数据,增加重量不再重新识别
if (presentation?.mealPickupMode == 0) { return
presentation?.updateWeight(weight)
lastWeight = weight
return@addWeightListener
} }
//重量小于等于5克时改为识别中页面
isAnalyzing = false
presentation?.step1FoodRecognizing()
return
} }
if (isPageVisible.not() || isStartRecognize.not()) { if (weight <= WEIGHT_RESET_RECOGNIZE) {
if (ActivityManager.currentActivity() is MainActivity) { //秤上重量过下,显示识别中页面
isPageVisible = true presentation?.step1FoodRecognizing()
isStartRecognize = true return
}
return@addWeightListener
} }
//0.05
// val isWeightChange = abs(weight - lastWeight) > 0.02 // val isWeightChange = abs(weight - lastWeight) > 0.02
val isWeightChange = weight - lastWeight > 0.02 val isWeightChange = weight - lastWeight > WEIGHT_CHANGE_VALUE
if (weight != lastWeight) { if (weight != lastWeight) {
log("recognizeByWeight---00001,weight=$weight,lastWeight=$lastWeight,isWeightChange=$isWeightChange") log("recognizeByWeight---00001,weight=$weight,lastWeight=$lastWeight,isWeightChange=$isWeightChange")
} }
recognizeByWeight(weight, 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) presentation?.updateWeight(weight)
if (weight <= 0.005) { if (weight <= WEIGHT_RESET_RECOGNIZE) {
log("recognizeByWeight---00002,秤重未超过5克") log("recognizeByWeight---00002,秤重未超过5克")
//检测到秤上没有东西,重新启动识别菜品 && presentation?.mealPickupMode == 1 //检测到秤上没有东西,重新启动识别菜品 && presentation?.mealPickupMode == 1
isRecognitionFood = true isRecognitionFood = true
@@ -374,9 +407,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// e.printStackTrace() // e.printStackTrace()
// list // list
// } // }
searchFoodList.clear()
searchFoodList.addAll(list)
adapter.notifyDataSetChanged() adapter.submitList(list)
binding.recyclerview.visible()
checkedItem = list[0].also { checkedItem = list[0].also {
it.photoUri = lastPhotoUri it.photoUri = lastPhotoUri
@@ -559,10 +593,14 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun clearFoodList() { fun clearRecognizeFood() {
//adapter.updateData(listOf()) log("clearRecognizeFood")
searchFoodList.clear() binding.recyclerview.invisible()
adapter.notifyDataSetChanged() adapter.submitList(null)
binding.tvToSearch.gone()
binding.previewView.visible()
binding.ivImg.gone()
} }
private fun updateDateTime() { private fun updateDateTime() {
@@ -594,7 +632,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
log("onResume-00001isRefreshPage=$isRefreshPage") log("onResume-00001isRefreshPage=$isRefreshPage")
if (presentation == null || !presentation!!.isShowing) { if (presentation == null || !presentation!!.isShowing) {
log("onResume-00002,副屏未显示,加载副屏") log("onResume-00002,副屏未显示,加载副屏")
lastWeight = 0.0 lastWeight = 0
setupSecondaryDisplay() setupSecondaryDisplay()
presentation?.step1FoodRecognizing() presentation?.step1FoodRecognizing()
} else { } else {
@@ -603,7 +641,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
isRefreshPage = false isRefreshPage = false
//已显示副屏,则进行更新 //已显示副屏,则进行更新
val weight = lastWeight val weight = lastWeight
lastWeight = 0.0 lastWeight = 0
presentation?.hideRecImage() presentation?.hideRecImage()
presentation?.step1FoodRecognizing() presentation?.step1FoodRecognizing()
@@ -662,7 +700,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
eatWeight: Int, eatWeight: Int,
eatNum: Int, eatNum: Int,
userId: String?, userId: String?,
isMember:Boolean, isMember: Boolean,
notEnoughOneBlock: () -> Unit = {}, notEnoughOneBlock: () -> Unit = {},
successBlock: () -> Unit successBlock: () -> Unit
) { ) {
@@ -800,36 +838,36 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
//0-计费,1-不计费 //0-计费,1-不计费
val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) ?: 0 val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) ?: 0
var foodWeight = 0.0 var foodWeight = 0
var eatWeight = 0.0 var eatWeight = 0
if (chargeMode == 0) { if (chargeMode == 0) {
//计费 //计费
if (mealPickupMode == 0) { if (mealPickupMode == 0) {
//即放即取 //即放即取
eatWeight = lastWeight * 1000 eatWeight = lastWeight
foodWeight = lastWeight * 1000 foodWeight = lastWeight
} else { } else {
//余量计量 //余量计量
eatWeight = (recognizeWeight - lastWeight) * 1000 eatWeight = recognizeWeight - lastWeight
foodWeight = recognizeWeight * 1000 foodWeight = recognizeWeight
log("eatWeight=$eatWeight, recognizeWeight=$recognizeWeight, lastWeight=$lastWeight") log("eatWeight=$eatWeight, recognizeWeight=$recognizeWeight, lastWeight=$lastWeight")
} }
} else { } else {
//不计费 //不计费
foodWeight = recognizeWeight * 1000 foodWeight = recognizeWeight
eatWeight = if (mealPickupMode == 0) { eatWeight = if (mealPickupMode == 0) {
//即放即取 //即放即取
recognizeWeight * 1000 recognizeWeight
} else { } else {
//余量计量 //余量计量
(recognizeWeight - lastWeight) * 1000 recognizeWeight - lastWeight
} }
} }
val eatNum = getEatNum(eatWeight, checkedItem!!.specWeight) val eatNum = getEatNum(eatWeight.toDouble(), checkedItem!!.specWeight)
createOrder( createOrder(
foodInfo = checkedItem!!, foodInfo = checkedItem!!,
foodWeight = foodWeight.roundToInt(), foodWeight = foodWeight,
eatWeight = eatWeight.roundToInt(), eatWeight = eatWeight,
eatNum = eatNum, eatNum = eatNum,
userId = null, userId = null,
isMember = false isMember = false
@@ -956,7 +994,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// private val dealyMillis = 10 * 60 * 1000L // private val dealyMillis = 10 * 60 * 1000L
private val initialDelay = 10 * 1000L private val initialDelay = 10 * 1000L
private val dealyMillis = 5 * 1000L private val dealyMillis = 5 * 1000L
// private var taskPageNo = 1
// private var taskPageNo = 1
fun startFaceTask() { fun startFaceTask() {
faceTaskJob = faceTaskJob =
intervalExecutor.startIntervalTaskWithInitialDelay(initialDelay, dealyMillis) { intervalExecutor.startIntervalTaskWithInitialDelay(initialDelay, dealyMillis) {
@@ -1097,13 +1136,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} }
/**
* 隐藏搜索按钮
*/
fun hideSearchView() {
binding.tvToSearch.gone()
}
// @Subscribe(threadMode = ThreadMode.MAIN) // @Subscribe(threadMode = ThreadMode.MAIN)
// public fun onResetBox(event: ResetBoxEvent) { // public fun onResetBox(event: ResetBoxEvent) {
// ObjectBox.boxStore.close() // ObjectBox.boxStore.close()
@@ -77,8 +77,8 @@ class BusinessFragment: BaseFragment<FragmentBusinessBinding>() {
} }
} }
SensorScaleUtils.addWeightListener { value -> SensorScaleUtils.addWeightListener { value ->
val realWeight = (value * 1000).roundToInt() //val realWeight = (value * 1000).roundToInt()
binding.tvFoodWeight.text = "$realWeight" binding.tvFoodWeight.text = "$value"
} }
} }
} }
@@ -10,19 +10,21 @@ import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder 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.dp
import com.sw.dualscreen.ext.format2String 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 import com.sw.dualscreen.model.response.FoodItem
class FoodOrderAdapter(var list: MutableList<FoodItem>) : class FoodOrderAdapter(var list: MutableList<FoodItem>) :
BaseQuickAdapter<FoodItem, FoodOrderAdapter.VH>(list) { BaseQuickAdapter<FoodItem, FoodOrderAdapter.VH>(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 { override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context) val inflater = LayoutInflater.from(context)
val binding = LayoutFoodListHeaderBinding.inflate(inflater, parent, false) val binding = ListItemFoodOrderBinding.inflate(inflater, parent, false)
return VH(binding) return VH(binding)
} }
@@ -31,9 +33,20 @@ class FoodOrderAdapter(var list: MutableList<FoodItem>) :
val binding = holder.binding val binding = holder.binding
item?.let { item?.let {
binding.tvFoodName.text = it.foodName 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.tvWeight.text = "${it.num}"
binding.tvAmount.text = it.price.format2String(2) 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) setTextColor(binding.tvFoodName, binding.tvPriceNorm, binding.tvWeight, binding.tvAmount)
binding.root.updateLayoutParams<RecyclerView.LayoutParams> { binding.root.updateLayoutParams<RecyclerView.LayoutParams> {
@@ -177,7 +177,10 @@ data class FoodItem(
val discount: Double = 0.0, val discount: Double = 0.0,
val income: Double = 0.0, val income: Double = 0.0,
val foodDifferenceId: Long = 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( data class FoodOrderModel(
@@ -5,24 +5,16 @@ import android.annotation.SuppressLint
import android.app.Presentation import android.app.Presentation
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Outline
import android.graphics.Point import android.graphics.Point
import android.hardware.Camera import android.hardware.Camera
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.util.DisplayMetrics
import android.view.Display import android.view.Display
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewOutlineProvider
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@@ -30,7 +22,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.arcsoft.face.ErrorInfo import com.arcsoft.face.ErrorInfo
import com.sw.dualscreen.BuildConfig import com.sw.dualscreen.BuildConfig
import com.sw.dualscreen.GlobalKey import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.MyApp
import com.sw.dualscreen.R import com.sw.dualscreen.R
import com.sw.dualscreen.activity.MainActivity import com.sw.dualscreen.activity.MainActivity
import com.sw.dualscreen.adapter.FoodOrderAdapter 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.gone
import com.sw.dualscreen.ext.load import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.maskName import com.sw.dualscreen.ext.maskName
import com.sw.dualscreen.ext.roundedDecimalPlace
import com.sw.dualscreen.ext.screenSize import com.sw.dualscreen.ext.screenSize
import com.sw.dualscreen.ext.visible import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.DinnerType 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.FacePreviewInfo
import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration 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
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel.REGISTER_STATUS_READY
import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@@ -105,14 +94,14 @@ class MainScreenPresentation(
private var irFaceRectTransformer: FaceRectTransformer? = null private var irFaceRectTransformer: FaceRectTransformer? = null
private var detectWeight = 0.0 //识别菜品时的重量 private var detectWeight = 0.0 //识别菜品时的重量
var lastWeight = 0.0 // 上一次的计算热量结果 var lastWeight = 0 // 上一次的计算热量结果
// private var userNutritionData: UserNutritionData? = null // private var userNutritionData: UserNutritionData? = null
private var userNutrition: UserNutrition? = null private var userNutrition: UserNutrition? = null
private var dinnerTypeInfo: DinnerType? = null private var dinnerTypeInfo: DinnerType? = null
private val debouncer = Debouncer(500) private val debouncer = Debouncer(500)
private var recognitionTime: Long = 0L // 人脸识别时的时间 private var recognitionTime: Long = 0L // 人脸识别时的时间
var recognitionWeight: Double = 0.0 // 人脸识别时的重量 var recognitionWeight: Int = 0 // 人脸识别时的重量
private var lastFaceTrackId: Int = -1 // 上一次的人脸信息 private var lastFaceTrackId: Int = -1 // 上一次的人脸信息
var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐 var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐
@@ -144,8 +133,8 @@ class MainScreenPresentation(
private var isFirstGetWeight = true private var isFirstGetWeight = true
fun updateWeight(weight: Double) { fun updateWeight(weight: Int) {
lastWeight = weight * 1000 // 将千克转成克 lastWeight = weight
Timber.tag(TAG) Timber.tag(TAG)
.d("updateWeight lastWeight = $weight, currentStep = $currentStep, isGoStep1 = $isGoStep1") .d("updateWeight lastWeight = $weight, currentStep = $currentStep, isGoStep1 = $isGoStep1")
//0-即放即取,1-余量计量 //0-即放即取,1-余量计量
@@ -164,14 +153,14 @@ class MainScreenPresentation(
// } // }
// isFirstGetWeight = true // isFirstGetWeight = true
// } // }
if (currentStep == 2 && lastWeight <= 5 && isGoStep1) { if (currentStep == 2 && lastWeight <= MainActivity.WEIGHT_RESET_RECOGNIZE && isGoStep1) {
//人脸识别过程中,秤上物品拿走 //人脸识别过程中,秤上物品拿走
isGoStep1 = false isGoStep1 = false
activity.runOnUiThread { activity.runOnUiThread {
Timber.tag(TAG).e("切回step1") Timber.tag(TAG).e("切回step1")
step1FoodRecognizing() step1FoodRecognizing()
} }
} else if (lastWeight <= 5) { } else if (lastWeight <= MainActivity.WEIGHT_RESET_RECOGNIZE) {
isGoStep1 = false isGoStep1 = false
activity.runOnUiThread { activity.runOnUiThread {
Timber.tag(TAG).e("切回step1") 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 currentStep = 3
stepChangeCallback(currentStep) stepChangeCallback(currentStep)
binding.llTopInfo.visible() setTopInfoVisible()
binding.flFoodDetail.gone()
//根据接口数据更新热量数据-------------------------- //根据接口数据更新热量数据--------------------------
userViewModel.getUserNutritionData(userId = userId) { nutrition -> userViewModel.getUserNutritionData(userId = userId) { nutrition ->
activity.runOnUiThread { activity.runOnUiThread {
@@ -491,6 +487,9 @@ class MainScreenPresentation(
* 餐品识别中 * 餐品识别中
*/ */
fun step1FoodRecognizing() { fun step1FoodRecognizing() {
if (currentStep == 1) {
return
}
Timber.tag(TAG).d("main,step1,耗时:${System.currentTimeMillis() - startTime}") Timber.tag(TAG).d("main,step1,耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
jointPaymentQueryFinish = false jointPaymentQueryFinish = false
@@ -505,7 +504,6 @@ class MainScreenPresentation(
// } // }
// return // return
//} //}
currentStep = 1
LightManager.closeGreenLight() LightManager.closeGreenLight()
LightManager.closeRedLight() LightManager.closeRedLight()
@@ -513,12 +511,9 @@ class MainScreenPresentation(
currentFood = null currentFood = null
// userNutritionData = null // userNutritionData = null
userNutrition = null userNutrition = null
recognitionWeight = 0.0 recognitionWeight = 0
stepChangeCallback(currentStep) setTopInfoVisible()
binding.llTopInfo.visible()
binding.flFoodDetail.gone()
binding.calorieInclude.root.gone() binding.calorieInclude.root.gone()
binding.nutritionInclude.root.gone() binding.nutritionInclude.root.gone()
@@ -537,8 +532,10 @@ class MainScreenPresentation(
binding.flRecognizeIr.gone() binding.flRecognizeIr.gone()
pauseCamera() pauseCamera()
activity.clearFoodList() activity.clearRecognizeFood()
activity.hideSearchView()
currentStep = 1
stepChangeCallback(currentStep)
} }
// fun foodRecSuccess(foodInfo: FoodInfo) { // fun foodRecSuccess(foodInfo: FoodInfo) {
@@ -560,9 +557,14 @@ class MainScreenPresentation(
/** /**
* 用户人脸识别中 * 用户人脸识别中
*/ */
fun step2FaceRecognizing(foodInfo: FoodInfo) { fun step2FaceRecognizing(foodInfo: FoodInfo, hideFoodDetail: Boolean = false) {
isGoStep1 = true isGoStep1 = true
Timber.tag(TAG).d("main,step2,耗时:${System.currentTimeMillis() - startTime}") Timber.tag(TAG).d("main,step2,耗时:${System.currentTimeMillis() - startTime}")
if (hideFoodDetail) {
setTopInfoVisible()
}
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
currentStep = 2 currentStep = 2
LightManager.closeRedLight() LightManager.closeRedLight()
@@ -586,7 +588,7 @@ class MainScreenPresentation(
dinnerTypeInfo = null dinnerTypeInfo = null
// userNutritionData = null // userNutritionData = null
userNutrition = null userNutrition = null
recognitionWeight = 0.0 recognitionWeight = 0
stepChangeCallback(currentStep) stepChangeCallback(currentStep)
currentFood = foodInfo currentFood = foodInfo
@@ -668,12 +670,12 @@ class MainScreenPresentation(
// } // }
} }
private fun calculateNutrition(weight1: Double) { private fun calculateNutrition(value: Int) {
if (currentFood == null || userNutrition == null) { if (currentFood == null || userNutrition == null) {
return return
} }
var weight = weight1 var weight = value
if (weight < 0) weight = 0.0 if (weight < 0) weight = 0
debouncer.debounce { debouncer.debounce {
Timber.tag(TAG) Timber.tag(TAG)
.d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight") .d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight")
@@ -684,7 +686,7 @@ class MainScreenPresentation(
currentFood!!, currentFood!!,
// userNutritionData!!, // userNutritionData!!,
userNutrition!!, userNutrition!!,
weight, weight.toDouble(),
dinnerType = dinnerType ?: "" dinnerType = dinnerType ?: ""
) )
// Timber.tag(TAG).d("calculateNutrition calcResultInfo = $calcResultInfo") // Timber.tag(TAG).d("calculateNutrition calcResultInfo = $calcResultInfo")
@@ -830,8 +832,23 @@ class MainScreenPresentation(
isRecognition = false isRecognition = false
recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) 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 var recognizeTime = 0L
private fun initArcViewModel() { private fun initArcViewModel() {
recognizeViewModel.setLiveType(livenessType) recognizeViewModel.setLiveType(livenessType)
@@ -1187,8 +1204,7 @@ class MainScreenPresentation(
} }
createOrder(notEnoughOneBlock = { createOrder(notEnoughOneBlock = {
if (activity.settlementMode == 0) { if (activity.settlementMode == 0) {
binding.flFoodDetail.gone() setTopInfoVisible()
binding.llTopInfo.visible()
} }
// if (mealPickupMode == 0) { // if (mealPickupMode == 0) {
currentStep = 2 currentStep = 2
@@ -1249,11 +1265,11 @@ class MainScreenPresentation(
//userViewModel.postUserNutritionData(listOf(userNutritionParam)) //userViewModel.postUserNutritionData(listOf(userNutritionParam))
activity.createOrder( activity.createOrder(
foodInfo = currentFood!!, foodInfo = currentFood!!,
foodWeight = lastWeight.roundToInt(), foodWeight = lastWeight,
eatWeight = eatWeight.roundToInt(), eatWeight = eatWeight,
eatNum = activity.getEatNum(eatWeight, currentFood!!.specWeight), eatNum = activity.getEatNum(eatWeight.toDouble(), currentFood!!.specWeight),
userId = currentUserId, userId = currentUserId,
isMember = isMember , isMember = isMember,
notEnoughOneBlock = notEnoughOneBlock, notEnoughOneBlock = notEnoughOneBlock,
successBlock = { successBlock = {
activity.runOnUiThread { activity.runOnUiThread {
@@ -1316,11 +1332,12 @@ class MainScreenPresentation(
binding.flFoodDetail.visible() binding.flFoodDetail.visible()
binding.detailInclude.let { binding.detailInclude.let {
it.root.updateLayoutParams { it.root.updateLayoutParams {
height = activity.screenSize[1]/2 height = activity.screenSize[1] / 2 + 120.dp
} }
it.tvFoodList.run { it.tvFoodList.run {
if (adapter == null) { if (adapter == null) {
layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false) layoutManager =
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
adapter = foodOrderAdapter adapter = foodOrderAdapter
} }
} }
@@ -1332,10 +1349,36 @@ class MainScreenPresentation(
} }
foodOrderAdapter.notifyDataSetChanged() foodOrderAdapter.notifyDataSetChanged()
binding.detailInclude.tvTotalWeight.text = "总重量:${model.eatWeightSum}" binding.detailInclude.tvTotalWeight.text = "总重量:${model.eatWeightSum}"
binding.detailInclude.tvTotalCalorie.text = "总热量:${model.calorie.roundToInt()}千卡" binding.detailInclude.tvTotalCalorie.text =
"总热量:${model.calorie.roundToInt()}千卡"
jointPaymentQueryFinish = true 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)
} }
@@ -7,7 +7,7 @@ import timber.log.Timber
import kotlin.math.roundToInt import kotlin.math.roundToInt
typealias Callback = (Double) -> Unit typealias Callback = (Double) -> Unit
typealias WeightCallback = (Double) -> Unit typealias WeightCallback = (Int) -> Unit
private const val TAG = "SensorScaleUtils" private const val TAG = "SensorScaleUtils"
@@ -45,7 +45,7 @@ object SensorScaleUtils {
} }
weightCallbackList.forEach { weightCallbackList.forEach {
it.invoke(value) it.invoke((value * 1000).roundToInt())
} }
} }
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/darker_gray"/>
<stroke android:color="#cdcdcd" android:width="1dp"/>
<corners android:radius="5dp"/>
</shape>
@@ -285,7 +285,7 @@
<TextView <TextView
android:id="@+id/meatTv" android:id="@+id/meatTv"
style="@style/takeFoodNameTv" style="@style/takeFoodNameTv"
android:text="肉" android:text="肉蛋豆"
android:textSize="20sp" android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
@@ -10,7 +10,7 @@
android:id="@+id/tvFoodName" android:id="@+id/tvFoodName"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="2.5" android:layout_weight="2.1"
android:text="菜品名称" android:text="菜品名称"
android:textColor="#FF889AC2" android:textColor="#FF889AC2"
android:textSize="26sp" android:textSize="26sp"
@@ -23,7 +23,7 @@
android:id="@+id/tvPriceNorm" android:id="@+id/tvPriceNorm"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1.0" android:layout_weight="1.6"
android:text="规格" android:text="规格"
android:textColor="#FF889AC2" android:textColor="#FF889AC2"
android:textSize="26sp" android:textSize="26sp"
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:gravity="center_vertical"
xmlns:tools="http://schemas.android.com/tools">
<!-- 菜品名称列,权重2.5 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2.1"
android:gravity="center_vertical">
<TextView
android:id="@+id/tvFoodName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="菜品名称"
android:textColor="#FF889AC2"
android:textSize="25sp"
android:paddingHorizontal="5dp"
android:singleLine="true"
android:gravity="center_vertical|start" />
<TextView
android:id="@+id/tvLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="档口"
android:textColor="@color/black"
android:textSize="13sp"
android:background="@drawable/bg_order_flag"
android:paddingHorizontal="5dp"
android:paddingVertical="1dp"
android:visibility="gone"/>
</LinearLayout>
<!-- 规格列,权重1.0 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.6"
android:gravity="center">
<TextView
android:id="@+id/tvPriceNorm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="规格"
android:textColor="#FF889AC2"
android:textSize="25sp"
android:paddingHorizontal="5dp"
android:singleLine="true"
android:gravity="center" />
<TextView
android:id="@+id/tvPriceFlag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="[大份]"
android:textColor="@color/black"
android:textSize="15sp"
android:paddingHorizontal="5dp"
android:singleLine="true"
android:gravity="center"
android:visibility="gone"/>
</LinearLayout>
<!-- 重量列,权重1.0 -->
<TextView
android:id="@+id/tvWeight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
tools:text="重量(克)"
android:textColor="#FF889AC2"
android:textSize="25sp"
android:paddingHorizontal="5dp"
android:singleLine="true"
android:gravity="center" />
<!-- 小计列,权重1.0 -->
<TextView
android:id="@+id/tvAmount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
tools:text="小计(元)"
android:textColor="#FF889AC2"
android:textSize="25sp"
android:paddingHorizontal="5dp"
android:singleLine="true"
android:gravity="center" />
</LinearLayout>
+13 -2
View File
@@ -2,6 +2,7 @@
agp = "8.10.1" agp = "8.10.1"
core = "3.4.1" core = "3.4.1"
androidCore = "3.3.0" androidCore = "3.3.0"
eventbus = "3.2.0"
glide = "4.16.0" glide = "4.16.0"
kotlin = "2.0.21" kotlin = "2.0.21"
coreKtx = "1.10.1" coreKtx = "1.10.1"
@@ -14,6 +15,9 @@ activity = "1.8.0"
constraintlayout = "2.1.4" constraintlayout = "2.1.4"
accompanistPermissions = "0.37.3" accompanistPermissions = "0.37.3"
cameraCore = "1.4.1" cameraCore = "1.4.1"
objectboxVersion = "5.0.1"
refreshLayoutKernel = "3.0.0-alpha"
refreshHeaderClassics = "3.0.0-alpha"
retrofit = "3.0.0" retrofit = "3.0.0"
okhttp = "4.12.0" okhttp = "4.12.0"
timber = "5.0.1" timber = "5.0.1"
@@ -30,11 +34,13 @@ pytorch = "1.13.0"
recyclerview = "1.3.2" recyclerview = "1.3.2"
#baseQuickAdapter = "4.1.2" baseQuickAdapter = "3.0.4"
baseQuickAdapter4 = "4.1.2"
[libraries] [libraries]
android-core = { module = "com.google.zxing:android-core", version.ref = "androidCore" } android-core = { module = "com.google.zxing:android-core", version.ref = "androidCore" }
core = { module = "com.google.zxing:core", version.ref = "core" } 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" } glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
junit = { group = "junit", name = "junit", version.ref = "junit" } junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } 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" } hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } 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" } 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" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } 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-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } 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 = { group = "org.pytorch", name = "pytorch_android", version.ref = "pytorch" }
pytorch-android-torchvision = { group = "org.pytorch", name = "pytorch_android_torchvision", 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" } androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }