This commit is contained in:
2026-02-03 15:00:19 +08:00
parent 6e7eb80715
commit 7596924d75
24 changed files with 1216 additions and 342 deletions
@@ -18,12 +18,14 @@ import com.sw.dualscreen.R
import com.sw.dualscreen.databinding.DialogWaitingBinding
import com.sw.dualscreen.model.IActivityResult
import com.sw.dualscreen.model.response.PostEvent
import com.sw.dualscreen.utils.FileUtil
import com.sw.dualscreen.view.CustomDialog
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.plate.utils.ToastUtils
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import timber.log.Timber
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
@@ -131,6 +133,11 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
launchPermissionCallback?.callback(result)
}
fun log(msg: String) {
Timber.d(msg)
FileUtil.saveLog(msg)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onPostEvent(event: PostEvent) {
@@ -3,6 +3,7 @@ package com.sw.dualscreen.activity
import android.annotation.SuppressLint
import androidx.activity.viewModels
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.R
@@ -13,16 +14,12 @@ import com.sw.dualscreen.ext.addOnActionSearchListener
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.hideKeyboard
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.ResetBoxEvent
import com.sw.dualscreen.objbox.CollectedFoodInfo
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.ToastUtils
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import org.greenrobot.eventbus.EventBus
import kotlinx.coroutines.launch
class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
@@ -51,8 +48,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
override fun initialize() {
super.initialize()
box = ObjectBox.boxStore.boxFor(Food::class)
//binding.root.setOnClickListener { it.hideKeyboard() }
binding.root.setOnClickListener { it.hideKeyboard() }
binding.rvFoodList.let {
it.layoutManager = LinearLayoutManager(this)
it.adapter = adapter
@@ -103,9 +99,6 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
getCollectGoods()
}
private lateinit var box: Box<Food>
@SuppressLint("NotifyDataSetChanged")
private fun getCollectGoods(searchName: String? = null) {
// if (box == null) {
@@ -199,16 +192,13 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
showWaitingDialog("加载中……")
viewModel.deleteCollectFood(food.foodId, GlobalData.foodModelVersion) { deleteSuccess ->
if (deleteSuccess) {
Thread {
val filterFoodList = box.all.filter { it.foodName == food.foodName }
// Thread {}.start()
lifecycleScope.launch {
val filterFoodList = ObjectBox.filter(food.foodName)
filterFoodList.forEach { it.isDel = true }
box.put(filterFoodList)
// val filterIdList = filterFoodList.map { it.id }
////// ObjectBox.boxStore.runInTx {
//// box.removeByIds(filterIdList)
////// EventBus.getDefault().post(ResetBoxEvent())
////// }
if (filterFoodList.isNotEmpty()) {
ObjectBox.putAll(filterFoodList)
}
runOnUiThread {
hideWaitingDialog()
@@ -218,7 +208,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
loadEmptyView()
}
}
}.start()
}
}
}
}
@@ -2,6 +2,7 @@ package com.sw.dualscreen.activity
import android.content.Intent
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.databinding.ActivityInitBinding
import com.sw.dualscreen.model.response.FoodVector
@@ -10,13 +11,13 @@ import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.launch
class InitActivity : BaseActivity<ActivityInitBinding>() {
companion object {
private const val PAGE_SIZE = 100
}
private val userViewModel by viewModels<UserViewModel>()
private var pageNum = 1
@@ -28,12 +29,14 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
return ActivityInitBinding.inflate(layoutInflater)
}
private fun getCollectedFoodVector(block:()-> Unit) {
userViewModel.getCollectedFoodVector(param = mutableMapOf(
"pageNum" to "$pageNum",
"pageSize" to "$PAGE_SIZE",
"version" to GlobalData.foodModelVersion
)) { items ->
private fun getCollectedFoodVector(block: () -> Unit) {
userViewModel.getCollectedFoodVector(
param = mutableMapOf(
"pageNum" to "$pageNum",
"pageSize" to "$PAGE_SIZE",
"version" to GlobalData.foodModelVersion
)
) { items ->
val list = items ?: emptyList()
if (pageNum == 1 && list.isEmpty()) {
block()
@@ -51,32 +54,37 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
}
}
}
// private val box by lazy { ObjectBox.boxStore.boxFor(Food::class) }
// private val box by lazy { ObjectBox.boxStore.boxFor(Food::class) }
private fun saveFoodVector(list: List<FoodVector>) {
val vectorList = list.map { vt ->
val foodVector = vt.foodVector?.removeSurrounding("[", "]")?.split(",")?.map { it.toFloatOrNull()?:0.0f }?.toFloatArray()
Food(
collectId = vt.id,
foodId = vt.foodId,
foodName = vt.foodName,
version = vt.version,
foodVector = foodVector
)
lifecycleScope.launch {
val vectorList = list.map { vt ->
val foodVector = vt.foodVector?.removeSurrounding("[", "]")?.split(",")
?.map { it.toFloatOrNull() ?: 0.0f }?.toFloatArray()
Food(
collectId = vt.id,
foodId = vt.foodId,
foodName = vt.foodName,
version = vt.version,
foodVector = foodVector
)
}
ObjectBox.putAll(vectorList)
}
val box = ObjectBox.boxStore.boxFor(Food::class)
box.put(vectorList)
}
override fun initialize() {
super.initialize()
showWaitingDialog("加载中……")
FoodModule.init(this) {
getCollectedFoodVector {
runOnUiThread {
hideWaitingDialog()
binding.root.postDelayed({
goMainActivity()
}, 1000)
lifecycleScope.launch {
FoodModule.init(this@InitActivity) {
getCollectedFoodVector {
runOnUiThread {
hideWaitingDialog()
binding.root.postDelayed({
goMainActivity()
}, 1000)
}
}
}
}
@@ -3,6 +3,7 @@ package com.sw.dualscreen.activity
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Outline
import android.hardware.display.DisplayManager
import android.net.Uri
@@ -21,11 +22,11 @@ import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import com.google.common.util.concurrent.ListenableFuture
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.adapter.DialogSearchFoodAdapter
import com.sw.dualscreen.adapter.MainFoodListAdapter
import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.dialog.RemindDialog
@@ -63,22 +64,21 @@ 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 io.objectbox.Box
import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
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
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
/**
@@ -111,7 +111,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
searchFoodList[index].isChecked = index == position
}
val item = searchFoodList[position]
Timber.d("itemClick ${item.foodName}, position = $position")
log("itemClick ${item.foodName}, position = $position")
item.photoUri = null
checkedItem = item
notifyDataSetChanged()
@@ -149,7 +149,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun initialize() {
super.initialize()
box = ObjectBox.boxStore.boxFor(Food::class)
isPageVisible = true
addBackEventListener()
initView()
@@ -177,6 +176,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
updateDateTime()
binding.ivSetting.setOnClickListener {
isRefreshPage = false
startActivity(Intent(this, SettingActivity::class.java))
}
binding.previewView.outlineProvider = object : ViewOutlineProvider() {
@@ -221,8 +221,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
pauseAnalysis()
recognizeWeight = lastWeight
Timber.tag(TAG)
.d("registerDataChange,副屏updateFood调用前耗时:${System.currentTimeMillis() - startTime}")
log("registerDataChange,副屏updateFood调用前耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
presentation?.updateFood(foodInfo)
binding.tvFoodName.text = foodInfo.foodName
@@ -239,7 +238,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun registerDataChange() {
super.registerDataChange()
SensorScaleUtils.addWeightListener { weight ->
Timber.d("registerDataChange weight = $weight")
log("registerDataChange weight = $weight")
if (isPageVisible.not() || isStartRecognize.not()) {
if (ActivityManager.currentActivity() is MainActivity) {
isPageVisible = true
@@ -247,7 +246,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
return@addWeightListener
}
val isWeightChange = weight - lastWeight > 0.05
val isWeightChange = abs(weight - lastWeight) > 0.05
log("recognizeByWeight---00001,weight=$weight,lastWeight=$lastWeight,isWeightChange=$isWeightChange")
recognizeByWeight(weight, isWeightChange)
}
}
@@ -256,16 +256,19 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
presentation?.updateWeight(weight)
if (weight <= 0.005) {
log("recognizeByWeight---00002,未超过5克")
////余量取餐,检测到秤上没有东西,重新启动识别菜品 && presentation?.mealPickupMode == 1
isRecognitionFood = true
return
}
if (isWeightChange && isRecognitionFood) { // 大于50g
log("recognizeByWeight---00003,mealPickupMode=${presentation?.mealPickupMode}")
if (presentation?.mealPickupMode == 1) {
isRecognitionFood = false
}
debouncer.debounce {
log("recognizeByWeight---00004")
recognizeFood()
}
} else {
@@ -282,31 +285,30 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
LightManager.closeRedLight()
LightManager.openGreenLight()
showWaitingDialog("识别中,请稍后……")
takePhoto(
successCallback = { photoUri ->
Thread {
onTakePhotoSuccess(photoUri)
}.start()
failCount = 0
}, failureCallback = {
runOnUiThread {
if (failCount >= 10) {
//ToastUtils.showToast("相机异常,请稍后重试")
shutdownCamera()
setupCamera()
return@runOnUiThread
}
takePhoto(successCallback = { photoUri ->
Thread {
onTakePhotoSuccess(photoUri)
}.start()
failCount = 0
}, failureCallback = {
runOnUiThread {
if (failCount >= 10) {
ToastUtils.showToast("相机异常,请稍后重试")
shutdownCamera()
setupCamera()
return@runOnUiThread
}
failCount++
hideWaitingDialog()
}
failCount++
hideWaitingDialog()
shutdownCamera()
setupCamera()
shutdownCamera()
setupCamera()
binding.root.postDelayed({
recognizeFood()
}, 1000)
})
binding.root.postDelayed({
recognizeFood()
}, 1000)
})
}
/**
@@ -318,7 +320,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun updateFoodInfo(list: MutableList<FoodInfo>, scoreList: List<IdNameScore>) {
val queryData = GsonUtils.toJson(list)
val recData = GsonUtils.toJson(scoreList)
Timber.d("registerDataChange识别后查询接口数据:$queryData,识别数据:$recData")
log("registerDataChange识别后查询接口数据:$queryData,识别数据:$recData")
if (list.isEmpty()) {
binding.tvToSearch.let {
it.text = "未查询到,手动搜索"
@@ -359,24 +361,21 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
private fun setupCamera() {
Timber.d("setupCamera")
log("setupCamera")
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture!!.addListener({
val cameraProvider = cameraProviderFuture!!.get()
// 1. 创建预览用例
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(binding.previewView.surfaceProvider)
}
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding.previewView.surfaceProvider)
}
// 2. 创建图像分析用例(用于副屏显示)
imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
// .setTargetResolution(Size(640, 480)) // 降低分辨率减轻负担
.build()
.also { analysis ->
.build().also { analysis ->
analysis.setAnalyzer(executor) { imageProxy ->
// 仅在步骤1时传递
if (isAnalyzing) {
@@ -389,10 +388,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
// 3. 创建拍照用例
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
imageCapture =
ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
// .setTargetResolution(Size(1920, 1080)) // 设置拍照分辨率
.build()
.build()
// 4. 选择摄像头
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
@@ -405,20 +404,20 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageAnalysis, imageCapture
)
} catch (exc: Exception) {
Timber.e(exc.message)
} catch (e: Exception) {
log("setupCamera方法异常:${e.message}")
}
}, ContextCompat.getMainExecutor(this))
}
fun pauseAnalysis() {
Timber.d("pauseAnalysis")
log("pauseAnalysis")
isAnalyzing = false
imageAnalysis?.clearAnalyzer()
}
fun resumeAnalysis() {
Timber.d("resumeAnalysis isAnalyzing = $isAnalyzing")
log("resumeAnalysis isAnalyzing = $isAnalyzing")
if (isAnalyzing) return
// isAnalyzing = true
imageAnalysis?.setAnalyzer(executor) { imageProxy ->
@@ -434,7 +433,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
* 停止相机识别
*/
private fun shutdownCamera() {
Timber.d("shutdownCamera")
log("shutdownCamera")
try {
// 1. 首先停止图像分析
imageAnalysis?.clearAnalyzer()
@@ -449,13 +448,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// 4. 停止副屏更新
isAnalyzing = false
} catch (e: Exception) {
Timber.e(e, "Error shutting down camera")
log("Error shutting down camera:${e.message}")
}
}
// 拍照功能
private fun takePhoto(successCallback: (Uri) -> Unit, failureCallback: () -> Unit) {
Timber.d("takePhoto")
log("takePhoto")
// 临时停止分析以避免干扰
isAnalyzing = false
@@ -463,21 +462,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val executor = ContextCompat.getMainExecutor(this)
val cacheDir = cacheDir
val photoFile = File.createTempFile(
"IMG_${System.currentTimeMillis()}",
".jpg",
cacheDir
"IMG_${System.currentTimeMillis()}", ".jpg", cacheDir
)
val cacheOutputOptions =
ImageCapture.OutputFileOptions.Builder(photoFile).build()
val cacheOutputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
// 执行拍照
imageCapture?.takePicture(
cacheOutputOptions,
executor,
object : ImageCapture.OnImageSavedCallback {
cacheOutputOptions, executor, object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
val savedUri = outputFileResults.savedUri
Timber.d("takePhoto savedUri = $savedUri")
log("takePhoto savedUri = $savedUri")
if (savedUri != null) {
successCallback(savedUri)
}
@@ -486,14 +480,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
override fun onError(exception: ImageCaptureException) {
Timber.e("拍照失败: ${exception.message}")
log("takePhoto拍照失败: ${exception.message}")
failureCallback()
//ToastUtils.showToast("拍照失败: ${exception.message}")
// 恢复图像分析
isAnalyzing = true
}
}
)
})
}
private fun getSecondaryDisplay(): Display? {
@@ -522,7 +515,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
).apply {
setStepChangeCallback { step ->
if (step == 1) {
Timber.d("setStepChangeCallback${step}")
log("setStepChangeCallback${step}")
updateCurrentFood(null)
bottomSheetDialog?.dismiss()
}
@@ -560,12 +553,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} else {
//副屏未显示重新加载
isRecognitionFood = true
log("onResume-00001")
if (presentation == null || !presentation!!.isShowing) {
log("onResume-00002,副屏未显示,加载副屏")
lastWeight = 0.0
setupSecondaryDisplay()
presentation?.step1FoodRecognizing()
} else {
log("onResume-00003,副屏显示,更新副屏, isRefreshPage=$isRefreshPage")
if (isRefreshPage) {
isRefreshPage = false
//已显示副屏,则进行更新
val weight = lastWeight
lastWeight = 0.0
@@ -576,7 +573,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
recognizeByWeight(weight, true)
}, 500)
}
isRefreshPage = !isRefreshPage
}
}
@@ -627,7 +623,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
notEnoughOneBlock: () -> Unit = {},
block: () -> Unit
) {
Timber.tag(TAG).d("foodWeight=$foodWeight,eatWeight=$eatWeight")
log("foodWeight=$foodWeight,eatWeight=$eatWeight")
val pickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
// if (pickupMode == 0) {
// if (foodWeight <= 5) {
@@ -735,10 +731,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private var isRefreshPage = false
@Subscribe(threadMode = ThreadMode.MAIN)
fun onClickBackEvent(event: ClickBackEvent) {
isRefreshPage = false
}
// @Subscribe(threadMode = ThreadMode.MAIN)
// fun onClickBackEvent(event: ClickBackEvent) {
// isRefreshPage = false
// }
private fun clickPayButton() {
if (checkedItem == null) {
@@ -761,7 +757,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
//余量计量
eatWeight = (recognizeWeight - lastWeight) * 1000
foodWeight = recognizeWeight * 1000
Timber.d("eatWeight=$eatWeight, recognizeWeight=$recognizeWeight, lastWeight=$lastWeight")
log("eatWeight=$eatWeight, recognizeWeight=$recognizeWeight, lastWeight=$lastWeight")
}
} else {
//不计费
@@ -782,7 +778,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
eatNum = eatNum,
userId = null,
) {
// TODO: 暂不关闭首页副屏
isRefreshPage = false
//presentation?.dismiss()
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, checkedItem!!)
@@ -814,13 +810,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
* 上传菜品信息
*/
private suspend fun uploadCollectFoodPics(
foodInfo: FoodInfo,
imageFile: File?,
imageVector: FloatArray?
foodInfo: FoodInfo, imageFile: File?, imageVector: FloatArray?
) {
if (imageFile == null || imageVector == null) {
Timber.tag(TAG)
.d("是否null判断,imageFile == null:${imageFile == null},imageVector == null:${imageVector == null}")
log("是否null判断,imageFile == null:${imageFile == null},imageVector == null:${imageVector == null}")
return
}
val foodId = foodInfo.foodId
@@ -834,53 +827,45 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val vectors = listOf(imageVector)
val foodVectorList = vectors.map {
it.joinToString(
separator = ",",
prefix = "[",
postfix = "]"
separator = ",", prefix = "[", postfix = "]"
)
}
val foodVectorJson =
foodVectorList.joinToString(separator = ",", prefix = "[", postfix = "]")
Timber.tag(TAG).d("json=$foodVectorJson")
log("json=$foodVectorJson")
params["foodVector"] = foodVectorJson.toRequestBody()
val idList = viewModel.uploadCollectFoodPics(files, params)
if (idList.isNullOrEmpty()) {
loadRemindDialog("上传失败,未返回向量数据id")
Timber.tag(TAG).d("idList为空")
log("idList为空")
return
}
Timber.tag(TAG)
.d("uploadCollectFoodPics-已采集向量总数:${box.all.filter { it.isDel.not() }.size}条")
val filterList = box.all.filter { it.collectId == idList[0] }
val all = ObjectBox.getAll()
val size = all.filter { it.isDel.not() }.size
log("uploadCollectFoodPics-已采集向量总数:${size}")
val filterList = all.filter { it.collectId == idList[0] }
if (filterList.isNotEmpty()) {
loadRemindDialog("返回的id${idList[0]}已存在")
return
}
Thread {
box.put(
Food(
collectId = idList[0],
foodId = foodId,
foodName = foodName,
foodVector = imageVector,
version = foodModelVersion
)
ObjectBox.put(
Food(
collectId = idList[0],
foodId = foodId,
foodName = foodName,
foodVector = imageVector,
version = foodModelVersion
)
}.start()
)
}
private fun loadRemindDialog(msg: String) {
runOnUiThread {
RemindDialog(
context = context,
content = msg,
confirmBlock = {}
).show()
context = context, content = msg, confirmBlock = {}).show()
}
}
private lateinit var box: Box<Food>
private fun uri2File(uri: Uri, block: (File?, FloatArray?) -> Unit) {
ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
val imageVector = try {
@@ -892,7 +877,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val imageFile = BitmapSaver.saveToAppFilesDir(
bitmap, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
)
Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${imageFile?.absolutePath}")
log("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${imageFile?.absolutePath}")
block(imageFile, imageVector)
if (bitmap.isRecycled.not()) {
bitmap.recycle()
@@ -913,8 +898,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// private val initialDelay = 5 * 60 * 1000L
// private val dealyMillis = 10 * 60 * 1000L
private val initialDelay = 60 * 1000L
private val dealyMillis = 30 * 1000L
private val initialDelay = 30 * 1000L
private val dealyMillis = 60 * 1000L
private var taskPageNo = 1
fun startFaceTask() {
faceTaskJob =
@@ -936,8 +921,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
updateFaceData(list)
}
}
)
})
}
}
@@ -952,9 +936,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} else {
//保存数据
val faceEntity = FaceEntity(
model.userId,
null,
Base64.decode(model.faceFeatureStr)
model.userId, null, Base64.decode(model.faceFeatureStr)
).also {
it.userType = "1"
}
@@ -988,66 +970,71 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun onTakePhotoSuccess(photoUri: Uri) {
lastPhotoUri = photoUri
Timber.tag(TAG).d("main,takePhoto耗时:${System.currentTimeMillis() - startTime}")
log("registerDataChange main,takePhoto耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
Timber.d("registerDataChange photoUri = ${photoUri.path}")
log("registerDataChange photoUri = ${photoUri.path}")
// viewModel.getIdentifiedFoodList()
ImageUtil.uriToBitmap(this, photoUri)?.let { bitmap ->
Timber.tag(TAG).d("main,uriToBitmap耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
Timber.d("registerDataChange photoUri 拿到bitmap")
lifecycleScope.launch {
ImageUtil.uriToBitmap(this@MainActivity, photoUri)?.let { bitmap ->
queryFoodData(bitmap)
}
}
}
private suspend fun queryFoodData(bitmap: Bitmap) {
log("registerDataChange main,uriToBitmap耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
log("registerDataChange photoUri 拿到bitmap")
// val bmp = BitmapCropper.cropCenter(bitmap, 1300, 900)
Timber.d("registerDataChange photoUri bitmap裁剪完成")
val file = BitmapSaver.saveToAppFilesDir(
bitmap, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
)
Timber.tag(TAG)
.d("main,saveToAppFilesDir耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
Timber.d("registerDataChange photoUri bitmap保存文件路径:${file?.absolutePath}")
//val nameList = FoodModule.queryFood(bitmap)
val scoreList = FoodModule.getFoodScoreList(bitmap)
log("registerDataChange registerDataChange photoUri bitmap裁剪完成")
val file = BitmapSaver.saveToAppFilesDir(
bitmap, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
)
log("registerDataChange main,saveToAppFilesDir耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
log("registerDataChange photoUri bitmap保存文件路径:${file?.absolutePath}")
//val nameList = FoodModule.queryFood(bitmap)
val scoreList = FoodModule.getFoodScoreList(bitmap)
val foodName = if (scoreList.isNotEmpty()) {
val recDataJson = GsonUtils.toJson(scoreList)
Timber.tag(TAG).d("main,getFoodScoreList耗时:${System.currentTimeMillis() - startTime}")
log("registerDataChange main,getFoodScoreList耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
Timber.d("registerDataChange photoUri 拿到识别数据:$recDataJson")
log("registerDataChange photoUri 拿到识别数据:$recDataJson")
val nameList = scoreList.map { it.name }
val foodName = nameList.joinToString(separator = ",")
nameList.joinToString(separator = ",")
} else ""
hideWaitingDialog()
log("registerDataChange photoUri 识别数据名称:$foodName")
runOnUiThread {
binding.flPay.run {
val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
//0-计费,1-不计费
if (chargeMode == 0) visible() else gone()
}
}
if (TextUtils.isEmpty(foodName)) {
LightManager.closeGreenLight()
LightManager.closeRedLight()
//binding.layoutRescan.visibility = View.VISIBLE
hideWaitingDialog()
Timber.d("registerDataChange photoUri 识别数据名称:$foodName")
runOnUiThread {
binding.flPay.run {
val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
//0-计费,1-不计费
if (chargeMode == 0) visible() else gone()
binding.tvToSearch.let {
it.text = "未识别到,手动搜索"
it.visible()
}
}
if (TextUtils.isEmpty(foodName)) {
LightManager.closeGreenLight()
LightManager.closeRedLight()
//binding.layoutRescan.visibility = View.VISIBLE
} else {
//binding.layoutRescan.visibility = View.GONE
showWaitingDialog("正在查询菜品信息,请稍后……")
viewModel.getFoodInfo(foodName) { list ->
runOnUiThread {
binding.tvToSearch.let {
it.text = "未识别到,手动搜索"
it.visible()
}
}
} else {
//binding.layoutRescan.visibility = View.GONE
showWaitingDialog("正在查询菜品信息,请稍后……")
viewModel.getFoodInfo(foodName) { list ->
runOnUiThread {
hideWaitingDialog()
Timber.tag(TAG)
.d("main,getFoodInfo耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
updateFoodInfo(list.toMutableList(), scoreList)
}
hideWaitingDialog()
log("registerDataChange main,getFoodInfo耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
updateFoodInfo(list.toMutableList(), scoreList)
}
}
}
}
@@ -34,9 +34,9 @@ class SettingActivity : BaseActivity<ActivitySettingBinding>() {
initBackDispatcher()
binding.include.let {
it.ivPageBack.setOnClickListener {
// val intent = Intent(this, MainActivity::class.java)
// startActivity(intent)
EventBus.getDefault().post(ClickBackEvent())
//// val intent = Intent(this, MainActivity::class.java)
//// startActivity(intent)
// EventBus.getDefault().post(ClickBackEvent())
finish()
}
it.tvPageTitle.text = "设置"
@@ -73,13 +73,13 @@ class SettingActivity : BaseActivity<ActivitySettingBinding>() {
private lateinit var backPressedCallback: OnBackPressedCallback
private fun initBackDispatcher() {
// 创建回调,true表示初始启用状态
backPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
EventBus.getDefault().post(ClickBackEvent())
}
}
// 注册回调,使用lifecycleOwner确保生命周期安全
onBackPressedDispatcher.addCallback(this, backPressedCallback)
// backPressedCallback = object : OnBackPressedCallback(true) {
// override fun handleOnBackPressed() {
//// EventBus.getDefault().post(ClickBackEvent())
// }
// }
// // 注册回调,使用lifecycleOwner确保生命周期安全
// onBackPressedDispatcher.addCallback(this, backPressedCallback)
}
@@ -19,7 +19,6 @@ import com.sw.dualscreen.activity.CollectedFoodActivity
import com.sw.dualscreen.activity.SettingActivity
import com.sw.dualscreen.adapter.CollectFoodListAdapter
import com.sw.dualscreen.adapter.FoodCollectionAdapter
import com.sw.dualscreen.adapter.DialogSearchFoodAdapter
import com.sw.dualscreen.databinding.FragmentCollectBinding
import com.sw.dualscreen.databinding.LayoutCameraPreviewBinding
import com.sw.dualscreen.ext.clickWithDebounce
@@ -35,14 +34,11 @@ import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.ImageUploader
import com.sw.dualscreen.utils.ImageUtil
import com.sw.plate.utils.ToastUtils
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import timber.log.Timber
import kotlin.getValue
@SuppressLint("NotifyDataSetChanged")
class CollectFragment : BaseFragment<FragmentCollectBinding>() {
@@ -55,13 +51,6 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
private var selectedFoodId: String? = ""
private var selectedFoodName: String? = ""
private var box: Box<Food>? = null
fun initBox() {
if (box == null) {
box = ObjectBox.boxStore.boxFor(Food::class)
}
}
private val foodCollectionList = mutableListOf<FoodCollectionBean>().apply {
repeat(MAX_COUNT) {
add(FoodCollectionBean(isShowCamera = true))
@@ -138,6 +127,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
e.printStackTrace()
settingActivity?.hideWaitingDialog()
ToastUtils.showToast("程序异常${e.message}")
settingActivity?.log("程序异常${e.message}")
}
}
@@ -152,13 +142,14 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
} catch (e: Exception) {
e.printStackTrace()
ToastUtils.showToast("操作失败")
settingActivity?.log("操作失败:${e.message}")
settingActivity?.hideWaitingDialog()
return
}
val file = BitmapSaver.saveToAppFilesDir(
bitmap, requireActivity(), "IMG_CROP_${System.currentTimeMillis()}.jpg"
)
Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}")
settingActivity?.log("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}")
activity?.runOnUiThread {
foodCollectionList[index].let {
@@ -187,6 +178,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
settingActivity?.hideWaitingDialog()
if (cameraErrorCount >= 10) {
ToastUtils.showToast("拍照异常,请重新操作")
settingActivity?.log("拍照异常,请重新操作:$errMsg")
cameraErrorCount = 0
return@takePhoto
}
@@ -305,8 +297,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
version = GlobalData.foodModelVersion
)
}
initBox()
box?.put(foodList)
ObjectBox.putAll(foodList)
activity?.runOnUiThread {
batch.forEach { it.isFinish = true }
collectionAdapter.notifyDataSetChanged()
@@ -54,27 +54,29 @@ class CashPayFragment : BaseFragment<FragmentCashPayBinding>() {
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (hidden) {
delayDismiss()
dismissSubScreen()
return
}
//showSubScreen()
}
override fun onDestroy() {
delayDismiss()
dismissSubScreen()
super.onDestroy()
}
private fun delayDismiss() {
presentation?.dismiss()
//binding.root.postDelayed({
// presentation?.dismiss()
//}, 100)
private fun dismissSubScreen() {
presentation?.let {
if (it.isShowing) {
it.dismiss()
}
}
}
private fun showSubScreen() {
// 查找副屏(通常索引为1
if (displays.size > 1) {
dismissSubScreen()
presentation = CashPayPresentation(activity = payActivity, display = displays[1]) {
presentation?.dismiss()
}.also {
@@ -24,7 +24,7 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
// }
payActivity.foodInfo?.let {
foodName = it.foodName
payAmount = (it.vipPrice?:0.0) * payActivity.eatNum
payAmount = (it.vipPrice ?: 0.0) * payActivity.eatNum
}
showSubScreen()
}
@@ -32,22 +32,23 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (hidden) {
delayDismiss()
dismissSubScreen()
return
}
//showSubScreen()
}
override fun onDestroy() {
delayDismiss()
dismissSubScreen()
super.onDestroy()
}
private fun delayDismiss() {
presentation?.dismiss()
//binding.root.postDelayed({
// presentation?.dismiss()
//}, 100)
private fun dismissSubScreen() {
presentation?.let {
if (it.isShowing) {
it.dismiss()
}
}
}
fun loadBitmap(frame: Bitmap) {
@@ -57,6 +58,7 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
private fun showSubScreen() {
// 查找副屏(通常索引为1
if (displays.size > 1) {
dismissSubScreen()
presentation = FacePayPresentation(
activity = payActivity,
display = displays[1],
@@ -1,14 +1,11 @@
package com.sw.dualscreen.activity.fragment.pay
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.activity.fragment.BaseFragment
import com.sw.dualscreen.databinding.FragmentNumberPayBinding
import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.hideKeyboard
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.presentation.pay.CashPayPresentation
import com.sw.dualscreen.utils.SPUtil
import com.sw.plate.utils.ToastUtils
class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
@@ -85,27 +82,29 @@ class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (hidden) {
delayDismiss()
dismissSubScreen()
return
}
//showSubScreen()
}
override fun onDestroy() {
delayDismiss()
dismissSubScreen()
super.onDestroy()
}
private fun delayDismiss() {
presentation?.dismiss()
//binding.root.postDelayed({
// presentation?.dismiss()
//}, 100)
private fun dismissSubScreen() {
presentation?.let {
if (it.isShowing) {
it.dismiss()
}
}
}
private fun showSubScreen() {
// 查找副屏(通常索引为1
if (displays.size > 1) {
dismissSubScreen()
presentation = CashPayPresentation(activity = payActivity, display = displays[1]) {
presentation?.dismiss()
}.also {
@@ -283,7 +283,7 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
private val intervalExecutor by lazy { IntervalExecutor() }
private var payTaskJob: Job? = null
fun paySuccessCallback(callback: () -> Unit) {
payTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(5000, 10000) {
payTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(200, 500) {
payActivity?.queryOrderState { paySuccess ->
if (paySuccess) {
callback()
@@ -5,7 +5,6 @@ import android.text.SpannedString
import android.text.style.AbsoluteSizeSpan
import androidx.core.text.buildSpannedString
import androidx.lifecycle.lifecycleScope
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.activity.fragment.BaseFragment
import com.sw.dualscreen.ext.load
@@ -62,29 +61,31 @@ class ScanQrCodePayFragment : BaseFragment<FragmentScanQrcodePayBinding>() {
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (hidden) {
delayDismiss()
dismissSubScreen()
return
}
//showSubScreen()
}
override fun onDestroy() {
delayDismiss()
dismissSubScreen()
countDownJob?.cancel() // 自动取消订阅,防止内存泄漏
payTaskJob?.cancel()
super.onDestroy()
}
private fun delayDismiss() {
presentation?.dismiss()
//binding.root.postDelayed({
// presentation?.dismiss()
//}, 100)
private fun dismissSubScreen() {
presentation?.let {
if (it.isShowing) {
it.dismiss()
}
}
}
private fun showSubScreen() {
// 查找副屏(通常索引为1
if (displays.size > 1) {
dismissSubScreen()
presentation =
ScanQrCodePayPresentation(activity = payActivity, type = 0, display = displays[1]) {
presentation?.dismiss()
@@ -123,7 +124,7 @@ class ScanQrCodePayFragment : BaseFragment<FragmentScanQrcodePayBinding>() {
private val intervalExecutor by lazy { IntervalExecutor() }
private var payTaskJob: Job? = null
fun paySuccessCallback(isVip: Boolean) {
payTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(5000, 10000) {
payTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(200, 500) {
payActivity.queryOrderState { paySuccess ->
if (paySuccess) {
payActivity.showPaySuccess(isVip)