营养数据计算优化;人脸增加数据处理;其它优化;

This commit is contained in:
2025-12-25 18:57:26 +08:00
parent f080a8b73c
commit dfb734e25d
29 changed files with 1350 additions and 64 deletions
@@ -36,23 +36,35 @@ 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
import com.sw.dualscreen.model.response.UserFaceModel
import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.FoodModule.IdNameScore
import com.sw.dualscreen.presentation.MainScreenPresentation
import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.socket.LanServer
import com.sw.dualscreen.socket.TcpClient
import com.sw.dualscreen.utils.BitmapSaver
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.GsonUtils
import com.sw.dualscreen.utils.ImageUtil
import com.sw.dualscreen.utils.IntervalExecutor
import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.utils.SpTool
import com.sw.dualscreen.view.CustomBottomSheetDialog
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.face.collect.view.LanServerListenerImpl
import com.sw.face.collect.view.TcpClientListenerImpl
import com.sw.plate.utils.Base64
import com.sw.plate.utils.LightManager
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.facedb.FaceDatabase
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.Job
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject
import timber.log.Timber
import java.io.File
import java.time.LocalDateTime
@@ -127,6 +139,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun initialize() {
super.initialize()
isPageVisible = true
addBackEventListener()
FoodModule.init(this)
initView()
@@ -140,6 +153,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun initData() {
// viewModel.getEquipmentToken()
//viewModel.getUserFaceCache2()
startFaceTask()
// addSocketListener()
}
private fun initView() {
@@ -150,7 +167,18 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
//
// Log.d("ScreenInfo", "DPI: $screenDPI, density: $density");
viewModel.activeEngine()
viewModel.getDeviceConfig { deviceConfig ->
runOnUiThread {
if (deviceConfig == null) {
ToastUtils.showToast("获取设备配置数据失败")
return@runOnUiThread
}
GlobalData.appId = deviceConfig.arcsoftAppId ?: ""
GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: ""
GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: ""
viewModel.activeEngine()
}
}
updateDateTime()
binding.ivSetting.setOnClickListener {
startActivity(Intent(this, SettingActivity::class.java))
@@ -292,7 +320,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
SensorScaleUtils.addWeightListener { weight ->
Timber.d("registerDataChange weight = $weight")
if (isPageVisible.not() || isStartRecognize.not()) return@addWeightListener
if (isPageVisible.not() || isStartRecognize.not()) {
return@addWeightListener
}
val isWeightChange = weight - lastWeight > 0.05
recognizeByWeight(weight, isWeightChange)
}
@@ -607,6 +637,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (displays.size > 1) return displays[1]
return null
}
private val recognizeViewModel by lazy { viewModels<RecognizeViewModel>().value }
private fun setupSecondaryDisplay() {
val secondaryDisplay = getSecondaryDisplay()
@@ -619,7 +650,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
activity = this,
display = secondaryDisplay,
userViewModel = viewModel,
recognizeViewModel = viewModels<RecognizeViewModel>().value
recognizeViewModel = recognizeViewModel
).apply {
setStepChangeCallback { step ->
if (step == 1) {
@@ -653,13 +684,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
adapter.notifyDataSetChanged()
}
override fun onDestroy() {
//SensorScaleUtils.closeScale()
presentation?.cancel()
super.onDestroy()
shutdownCamera()
}
private fun updateDateTime() {
val formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 E", Locale.CHINA)
val dateTime = formatter.format(LocalDateTime.now(ZoneId.of("Asia/Shanghai")))
@@ -696,7 +720,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.root.postDelayed({
recognizeByWeight(weight, true)
},500)
}, 500)
}
isRefreshPage = !isRefreshPage
}
@@ -763,6 +787,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
return
}
}
if (eatNum == 0) {
ToastUtils.showToast("您好,当前重量不足一份")
return
}
val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
val order = FoodOrder(
deviceId = GlobalData.deviceId,
@@ -836,7 +864,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
}
private var isRefreshPage = false
@Subscribe(threadMode = ThreadMode.MAIN)
fun onClickBackEvent(event: ClickBackEvent) {
isRefreshPage = false
@@ -893,4 +923,168 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
override fun onDestroy() {
//SensorScaleUtils.closeScale()
faceTaskJob?.cancel()
presentation?.cancel()
shutdownCamera()
super.onDestroy()
}
private val intervalExecutor by lazy { IntervalExecutor() }
private var faceTaskJob: Job? = null
// private val initialDelay = 5 * 60 * 1000L
// private val dealyMillis = 10 * 60 * 1000L
private val initialDelay = 60 * 1000L
private val dealyMillis = 30 * 1000L
private var taskPageNo = 1
fun startFaceTask() {
faceTaskJob =
intervalExecutor.startIntervalTaskWithInitialDelay(initialDelay, dealyMillis) {
viewModel.getFaceIncrementList(
pageNo = taskPageNo,
timestamp = SpTool.getLastFaceTimestamp()
) { list ->
runOnUiThread {
if (list.isEmpty()) {
return@runOnUiThread
}
SpTool.setLastFaceTimestamp(System.currentTimeMillis())
updateFaceData(list)
}
}
}
}
private fun updateFaceData(list: List<UserFaceModel>) {
Thread {
val faceList = mutableListOf<FaceEntity>()
try {
list.forEach { model ->
if (model.faceDeleted == true) {
//删除数据
FaceDatabase.getInstance(this).faceDao().deleteFaceById(model.userId)
} else {
//保存数据
val faceEntity = FaceEntity(
model.userId,
null,
Base64.decode(model.faceFeatureStr)
).also {
it.userType = "1"
}
faceList.add(faceEntity)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
try {
if (faceList.isNotEmpty()) {
FaceDatabase.getInstance(this).faceDao().insert(faceList)
}
recognizeViewModel.refreshFaceList();
} catch (e: Exception) {
e.printStackTrace()
}
}.start()
}
private fun sendFaceData(faceData: String) {
// 给某个客户端发送
val jsonObject = JSONObject().also {
it.put("type", "faceFeature")
it.put("content", faceData)
}
tcpClient?.send(jsonObject)
}
private var tcpClient: TcpClient? = null
// private fun addSocketListener() {
// //val ipAddress = NetworkUtils.getIPAddress(true)
// //Log.d(TAG, "addSocketListener,ipAddress: $ipAddress");
// tcpClient = TcpClient(
// "192.168.1.95",
// 5000,
// GlobalData.deviceId, // clientId
// 5000, // connectTimeoutMs
// 10 * 1000, // heartbeatIntervalMs
// 30 * 1000 // heartbeatTimeoutMs
// )
//
// tcpClient?.setListener(object : TcpClientListenerImpl() {
// override fun onSendSuccess(json: JSONObject?) {
// super.onSendSuccess(json)
//// toast("发送成功")
// }
//
// override fun onSendFailed(json: JSONObject?, e: java.lang.Exception?) {
// super.onSendFailed(json, e)
// ToastUtils.showToast("发送失败${e?.message}")
// }
//
// override fun onMessage(json: JSONObject?) {
// super.onMessage(json)
// json?.let { receiveMessage(json!!) }
// }
// })
// tcpClient?.start();
//
// try {
// LanServer.getInstance().let {
// it.setListener(object : LanServerListenerImpl() {
// override fun onMessageReceived(clientId: String?, message: JSONObject?) {
// super.onMessageReceived(clientId, message)
// //toast("收到消息clientId=$clientId")
// }
// })
// it.start()
// }
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }
// /**
// * 接收服务端发送的消息
// *
// * @param json 人脸数据
// */
// private fun receiveMessage(json: JSONObject) {
// try {
// val faceId = json.getString("faceId");
// val faceFeature = json.getString("faceFeature");
// queryByUserName(faceId, { faceEntity ->
// if (faceEntity != null) {
// //已存在用户faceId的人脸数据
// return@queryByUserName
// }
// //不存在用户faceId,保存数据
// val faceEntity2 = FaceEntity(faceId, null, Base64.decode(faceFeature))
// //设置用户类型:1-内部员工、2-临时用户、3-普通会员、或者其它待定类型
// faceEntity2.setUserType("2")
// saveFaceData(faceEntity2)
// })
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }
// private fun saveFaceData(faceEntity: FaceEntity) {
// Thread {
// FaceDatabase.getInstance(this).faceDao().insert(faceEntity)
// }.start()
// }
//
// private fun queryByUserName(userName: String, block: (FaceEntity) -> Unit) {
// Thread {
// val faceEntity = FaceDatabase.getInstance(this).faceDao().queryByUserName(userName)
// runOnUiThread {
// block(faceEntity)
// }
// }.start()
// }
}
@@ -166,7 +166,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
return
}
settingActivity?.showWaitingDialog("拍照中……")
settingActivity?.showWaitingDialog("采集中……")
cameraUtils.takePhoto(cameraCallback) { errMsg ->
ToastUtils.showToast("拍照异常,请重新操作")
settingActivity?.hideWaitingDialog()
@@ -374,10 +374,8 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
clickIndex = -1
binding.editFoodName.setText("")
// foodList.clear()
// foodAdapter.updateData(mutableListOf())
// foodAdapter.notifyDataSetChanged()
//loadEmptyView()
searchFoodList.clear()
searchFoodAdapter.notifyDataSetChanged()
}
override fun onResume() {
@@ -48,8 +48,10 @@ class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
payActivity.getMemberInfoByPhone(phone, key) { memberInfo ->
if (memberInfo == null) {
payActivity.hideWaitingDialog()
//ToastUtils.showToast("查询会员信息失败,请稍后重试")
binding.root.postDelayed({
payActivity.hideWaitingDialog()
ToastUtils.showToast("未查询到会员信息,请稍后重试")
}, 1000)
return@getMemberInfoByPhone
}
//绑定订单使用faceUserId
@@ -137,7 +137,8 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
payActivity.getQrCodeImg(
orderId = payActivity.foodOrderId,
userId = memberInfo!!.id,
totalFee = payAmount.format2String(2)
//混合支付,实际支付金额
//totalFee = payAmount.format2String(2)
) { qrCodeImg ->
binding.ivPayQrCode.load(qrCodeImg)
//更新副屏二维码
@@ -44,7 +44,8 @@ class ScanQrCodePayFragment : BaseFragment<FragmentScanQrcodePayBinding>() {
//不需要绑定会员id
payActivity.getQrCodeImg(
orderId = payActivity.foodOrderId,
totalFee = payAmount.format2String(2)
//非会员扫码支付,不用传金额,后端处理,混合支付要传
//totalFee = payAmount.format2String(2)
) {
payQrCodePic = it
binding.ivPayQrCode.load(payQrCodePic)