From 29188c594424dcdfd4e29c6b83327f9402813eda Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Fri, 28 Nov 2025 18:46:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=81=94=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/sw/dualscreen/MyApp.kt | 3 +- .../activity/CollectedDataActivity.kt | 6 +- .../activity/CollectedFoodActivity.kt | 17 +- .../sw/dualscreen/activity/InitActivity.kt | 29 +- .../sw/dualscreen/activity/MainActivity.kt | 27 +- .../com/sw/dualscreen/activity/PayActivity.kt | 25 +- .../sw/dualscreen/activity/SettingActivity.kt | 2 +- .../activity/fragment/CollectFragment.kt | 135 +- .../activity/fragment/pay/CashPayFragment.kt | 16 +- .../activity/fragment/pay/FacePayFragment.kt | 16 +- .../fragment/pay/NumberPayFragment.kt | 16 +- .../fragment/pay/ScanQrCodePayFragment.kt | 24 +- .../adapter/CollectedFoodAdapter.kt | 8 +- .../adapter/CollectedFoodNewAdapter.kt | 10 +- .../dualscreen/adapter/SearchFoodAdapter.kt | 2 +- .../dualscreen/model/response/ApiResponse.kt | 19 +- .../sw/dualscreen/model/response/DataBean.kt | 5 + .../model/response/DinnerTypeInfo.kt | 85 +- .../model/response/EquipmentInfo.kt | 10 +- .../sw/dualscreen/model/response/FoodInfo.kt | 559 +++--- .../model/response/UserFaceModel.kt | 21 +- .../sw/dualscreen/network/api/ApiService.kt | 106 +- .../network/interceptor/RequestInterceptor.kt | 6 +- .../java/com/sw/dualscreen/objbox/DataBean.kt | 17 +- .../presentation/MainScreenPresentation.kt | 86 +- .../SecondaryScreenPresentation.kt | 1766 ++++++++--------- .../dualscreen/repository/BaseRepository.kt | 14 +- .../dualscreen/repository/RemoteRepository.kt | 131 +- .../java/com/sw/dualscreen/utils/ImageUtil.kt | 9 + .../sw/dualscreen/viewmodel/BaseViewModel.kt | 28 +- .../dualscreen/viewmodel/DeviceViewModel.kt | 82 +- .../sw/dualscreen/viewmodel/UserViewModel.kt | 155 +- app/src/main/res/drawable/bg_search.xml | 2 +- app/src/main/res/layout/activity_init.xml | 6 +- app/src/main/res/layout/activity_main.xml | 58 +- .../main/res/layout/bottom_sheet_dialog.xml | 24 +- .../res/layout/list_item_collected_food.xml | 3 +- .../res/layout/presentation_main_screen.xml | 14 +- .../com/sw/plate/utils/arcface/FaceApi.java | 2 +- 39 files changed, 1882 insertions(+), 1662 deletions(-) create mode 100644 app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt diff --git a/app/src/main/java/com/sw/dualscreen/MyApp.kt b/app/src/main/java/com/sw/dualscreen/MyApp.kt index c0e77a0..902d5b0 100644 --- a/app/src/main/java/com/sw/dualscreen/MyApp.kt +++ b/app/src/main/java/com/sw/dualscreen/MyApp.kt @@ -22,8 +22,9 @@ class MyApp : App() { Timber.plant(Timber.DebugTree()) var deviceId = AppUtil.getUDID(this) Timber.d("UDID = ${AppUtil.getUDID(this)}") - deviceId = "3ea47dc0-3cf0-3c2f-909c-265a9a65572e" +// deviceId = "3ea47dc0-3cf0-3c2f-909c-265a9a65572e" GlobalData.deviceId = deviceId + GlobalData.appBaseUrl = "http://192.168.1.201:14801" ObjectBox.init(this) // 初始化崩溃处理器 CrashHandler.init(this) diff --git a/app/src/main/java/com/sw/dualscreen/activity/CollectedDataActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/CollectedDataActivity.kt index 9dc16f0..1527313 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/CollectedDataActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/CollectedDataActivity.kt @@ -11,7 +11,7 @@ //import com.sw.dualscreen.dialog.WarnDialog //import com.sw.dualscreen.ext.addOnActionSearchListener //import com.sw.dualscreen.ext.hideKeyboard -//import com.sw.dualscreen.objbox.CollectedFoodBean +//import com.sw.dualscreen.objbox.CollectedFoodInfo //import com.sw.dualscreen.objbox.Food //import com.sw.dualscreen.objbox.ObjectBox //import com.sw.dualscreen.viewmodel.BaseViewModel @@ -31,7 +31,7 @@ // return ActivityCollectedDataBinding.inflate(layoutInflater) // } // -// private val list: MutableList = mutableListOf() +// private val list: MutableList = mutableListOf() // private val adapter by lazy { // CollectedFoodAdapter(list).apply { // isStateViewEnable = true @@ -88,7 +88,7 @@ // queryList = queryList?.filter { it.name?.contains(searchName) == true } // } // queryList?.forEach { -// list.add(CollectedFoodBean(foodName = it.name)) +// list.add(CollectedFoodInfo(foodName = it.name)) // } // adapter.notifyDataSetChanged() // if (list.isEmpty()) { diff --git a/app/src/main/java/com/sw/dualscreen/activity/CollectedFoodActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/CollectedFoodActivity.kt index f54cc28..f4f3a05 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/CollectedFoodActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/CollectedFoodActivity.kt @@ -11,7 +11,7 @@ import com.sw.dualscreen.databinding.LayoutEmptySearchBinding import com.sw.dualscreen.dialog.WarnDialog import com.sw.dualscreen.ext.addOnActionSearchListener import com.sw.dualscreen.ext.hideKeyboard -import com.sw.dualscreen.objbox.CollectedFoodBean +import com.sw.dualscreen.objbox.CollectedFoodInfo import com.sw.dualscreen.objbox.Food import com.sw.dualscreen.objbox.ObjectBox import com.sw.dualscreen.viewmodel.BaseViewModel @@ -30,7 +30,7 @@ class CollectedFoodActivity : BaseActivity() { return ActivityCollectedFoodBinding.inflate(layoutInflater) } - private val list: MutableList = mutableListOf() + private val list: MutableList = mutableListOf() private val adapter by lazy { CollectedFoodNewAdapter(list).apply { isStateViewEnable = true @@ -88,7 +88,7 @@ class CollectedFoodActivity : BaseActivity() { val totalList = box?.all ?.filter { it.name!=null } ?.groupBy { it.name!! } - ?.map { CollectedFoodBean(foodName = it.key, count = it.value.size) } + ?.map { CollectedFoodInfo(foodName = it.key, foodCount = it.value.size) } //var queryMap:Map> ?= null if (searchName.isNullOrBlank().not()) { //queryMap = totalMap?.filter { it.key.contains(searchName) } @@ -106,8 +106,19 @@ class CollectedFoodActivity : BaseActivity() { loadEmptyView() } binding.root.hideKeyboard() + + viewModel.getCollectedFoodList(pageNo = pageNo) { + if (it.isNotEmpty()) { + list.addAll(it) + runOnUiThread { + adapter.notifyDataSetChanged() + } + } + } } + private var pageNo = 1 + private var emptyBinding: LayoutEmptySearchBinding? = null private fun loadEmptyView() { if (emptyBinding == null) { diff --git a/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt index dd9a3f5..78caa9f 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt @@ -29,20 +29,23 @@ class InitActivity : BaseActivity() { override fun initialize() { super.initialize() - val isSuccess = viewModel.checkEquipmentInfo() - if (isSuccess) { + binding.root.postDelayed({ goMainActivity() - return - } - binding.imgQr.setImageBitmap( - QRCodeUtil.generateQRCode( - content = GlobalData.deviceId, - size = 200 - ) - ) - binding.initButton.setOnClickListener { - viewModel.getDeviceToken() - } + }, 1000) +// val isSuccess = viewModel.checkEquipmentInfo() +// if (isSuccess) { +// goMainActivity() +// return +// } +// binding.imgQr.setImageBitmap( +// QRCodeUtil.generateQRCode( +// content = GlobalData.deviceId, +// size = 200 +// ) +// ) +// binding.initButton.setOnClickListener { +// viewModel.getDeviceToken() +// } } override fun registerDataChange() { 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 e15e81a..07638db 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt @@ -114,7 +114,8 @@ class MainActivity : BaseActivity() { } private fun initData() { - viewModel.getEquipmentToken() +// viewModel.getEquipmentToken() + viewModel.getUserFaceCache(pageNo = 1) // presentation?.step1() presentation?.step1FoodRecognizing() } @@ -200,10 +201,14 @@ class MainActivity : BaseActivity() { binding.tvFoodName.setOnClickListener { SensorScaleUtils.zero() } - binding.tvRescan.setOnClickListener { - debouncer.debounce { recognizeFood() } - } +// binding.tvRescan.setOnClickListener { +// debouncer.debounce { recognizeFood() } +// } binding.btnPay.setOnClickListener { + if (checkedItem == null) { + ToastUtils.showToast("暂无识别数据,请搜索选择") + return@setOnClickListener + } presentation?.dismiss() startActivity(Intent(this, PayActivity::class.java).apply { putExtra(PayActivity.FOOD_INFO, checkedItem) @@ -317,9 +322,14 @@ class MainActivity : BaseActivity() { if (TextUtils.isEmpty(foodName)) { LightManager.closeGreenLight() LightManager.closeRedLight() - binding.layoutRescan.visibility = View.VISIBLE + //binding.layoutRescan.visibility = View.VISIBLE + binding.flPay.visible() + binding.tvToSearch.let { + it.text = "未识别到,去手动搜索" + it.visible() + } } else { - binding.layoutRescan.visibility = View.GONE + //binding.layoutRescan.visibility = View.GONE viewModel.getFoodInfo(foodName) { list -> runOnUiThread { updateFoodInfo(list.toMutableList(), scoreList) @@ -367,7 +377,10 @@ class MainActivity : BaseActivity() { LightManager.closeRedLight() binding.flPay.visible() - binding.tvToSearch.visible() + binding.tvToSearch.let { + it.text = "以上都不是,手动搜索" + it.visible() + } } else { binding.flPay.gone() binding.tvToSearch.gone() diff --git a/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt index 73840e8..5f4a0e3 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt @@ -65,9 +65,7 @@ class PayActivity : BaseActivity() { if (binding.btnPayCash.isChecked) { return@setOnClickListener } - if (cashPayFragment == null) { - cashPayFragment = CashPayFragment() - } + cashPayFragment = CashPayFragment() showFragment(cashPayFragment!!, TAG_PAY_CASH) switchButton(false, true, false, false) } @@ -75,9 +73,7 @@ class PayActivity : BaseActivity() { if (binding.btnPayNumber.isChecked) { return@setOnClickListener } - if (numberPayFragment == null) { - numberPayFragment = NumberPayFragment() - } + numberPayFragment = NumberPayFragment() showFragment(numberPayFragment!!, TAG_PAY_NUMBER) switchButton(false, false, true, false) } @@ -92,9 +88,7 @@ class PayActivity : BaseActivity() { } private fun showScanQrCodePay() { - if (qrCodePayFragment == null) { - qrCodePayFragment = ScanQrCodePayFragment() - } + qrCodePayFragment = ScanQrCodePayFragment() showFragment(qrCodePayFragment!!, TAG_PAY_QR_CODE) switchButton(true, false, false, false) } @@ -107,9 +101,7 @@ class PayActivity : BaseActivity() { } fun showFacePay() { - if (facePayFragment == null) { - facePayFragment = FacePayFragment() - } + facePayFragment = FacePayFragment() showFragment(facePayFragment!!, TAG_PAY_FACE) switchButton(false, false, false, true) } @@ -149,9 +141,7 @@ class PayActivity : BaseActivity() { // } fun showPayResult() { - if (payResultFragment == null) { - payResultFragment = PayResultFragment() - } + payResultFragment = PayResultFragment() showFragment(payResultFragment!!, TAG_PAY_RESULT) } @@ -162,9 +152,10 @@ class PayActivity : BaseActivity() { facePayFragment?.presentation?.dismiss() super.onDestroy() } - private var scanQrCodePayPresentation: ScanQrCodePayPresentation?=null + + private var scanQrCodePayPresentation: ScanQrCodePayPresentation? = null fun paySuccess() { - showFragment(PayResultFragment(),"") + showFragment(PayResultFragment(), "") if (displays.size > 1) { scanQrCodePayPresentation = ScanQrCodePayPresentation( activity = this, diff --git a/app/src/main/java/com/sw/dualscreen/activity/SettingActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/SettingActivity.kt index 977bd4d..4aea54a 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/SettingActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/SettingActivity.kt @@ -15,7 +15,7 @@ import kotlin.text.replace class SettingActivity : BaseActivity() { - private val viewModel by viewModels() + val viewModel by viewModels() override fun getViewModel(): BaseViewModel { return viewModel } diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt index 12c909b..24d28c7 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt @@ -34,12 +34,16 @@ import com.sw.dualscreen.utils.ImageUtil import com.sw.plate.utils.ToastUtils import io.objectbox.Box import io.objectbox.kotlin.boxFor +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import timber.log.Timber +import java.io.File import kotlin.getValue class CollectFragment : BaseFragment() { companion object { + private const val TAG = "CollectFragment" const val MAX_COUNT = 5 } private var selectedFoodId: String? = "" @@ -59,7 +63,7 @@ class CollectFragment : BaseFragment() { SearchFoodAdapter(searchFoodList).apply { setOnItemClickListener { adapter, view, position -> checkedItem = searchFoodList[position] - selectedFoodId = checkedItem!!.id + selectedFoodId = checkedItem!!.foodId selectedFoodName = checkedItem!!.foodName val isChecked = checkedItem!!.isChecked searchFoodList[position].isChecked = isChecked.not() @@ -78,8 +82,11 @@ class CollectFragment : BaseFragment() { addOnItemChildClickListener(R.id.ivDelete) { _, _, position -> foodCollectionList[position].let { it.bitmap = null + it.imageVector = null + it.imageFile = null it.isShowCamera = true it.isFinish = false + it.uploadSuccess = false } notifyItemChanged(position) } @@ -91,28 +98,45 @@ class CollectFragment : BaseFragment() { private val cameraCallback: (Uri) -> Unit = { uri -> - val index = foodCollectionList.indexOfFirst { it.bitmap == null } - if (index == -1) { - ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据") - rerurn@cameraCallback - } - ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap -> -// val cropBitmap = BitmapCropper.cropCenter( -// original = bitmap, -// targetWidth = 1300, targetHeight = 900, -// //offsetX = 30, offsetY = 100 -// ) - val file = BitmapSaver.saveToAppFilesDir( - bitmap, requireActivity(), "IMG_CROP_${System.currentTimeMillis()}.jpg" - ) - Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}") - - foodCollectionList[index].let { - it.bitmap = bitmap - it.isShowCamera = false - it.imageUri = file?.toUri() + try { + val index = foodCollectionList.indexOfFirst { it.imageFile == null } + if (index == -1) { + ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据") + rerurn@cameraCallback } - collectionAdapter.notifyItemChanged(index) + ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap -> + // val cropBitmap = BitmapCropper.cropCenter( + // original = bitmap, + // targetWidth = 1300, targetHeight = 900, + // //offsetX = 30, offsetY = 100 + // ) + initBox() + val imageVector = try { + FoodModule.bitmap2FloatArray(bitmap) + } catch (e: Exception) { + e.printStackTrace() + ToastUtils.showToast("操作失败") + return@let + } + val file = BitmapSaver.saveToAppFilesDir( + bitmap, requireActivity(), "IMG_CROP_${System.currentTimeMillis()}.jpg" + ) + Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}") + + foodCollectionList[index].let { + it.imageVector = imageVector + it.bitmap = null + it.isShowCamera = false + it.imageFile = file + } + collectionAdapter.notifyItemChanged(index) + if (bitmap.isRecycled.not()) { + bitmap.recycle() + } + } + } catch (e: Exception) { + e.printStackTrace() + ToastUtils.showToast("程序异常") } } @@ -157,7 +181,9 @@ class CollectFragment : BaseFragment() { Toast.makeText(requireActivity(), "请拍摄菜品照片", Toast.LENGTH_SHORT).show() return@setOnClickListener } - vectorThread() + vectorThread(){ + upload() + } } binding.editFoodName.setOnEditorActionListener { v, actionId, event -> @@ -190,13 +216,43 @@ class CollectFragment : BaseFragment() { } } - private fun vectorThread() { + private fun uploadCollectFoodPics(files: List, params: HashMap, callback: (Boolean) -> Unit) { + (requireActivity() as SettingActivity).viewModel.uploadCollectFoodPics(files,params, callback) + } + + private fun upload() { + val params = HashMap() + //params["placeId"] = restId.toRequestBody() + params["foodId"] = checkedItem!!.foodId.toRequestBody() + params["foodName"] = checkedItem!!.foodName!!.toRequestBody() + //params["foodVector"] = foodVector.toRequestBody() + for (index in foodCollectionList.indices step 5) { + val end = if(index + 5 < foodCollectionList.size - 1) index + 5 else foodCollectionList.size - 1 + val subList = foodCollectionList.subList(index, end) + val subFiles = subList.map { it.imageFile } + uploadCollectFoodPics(subFiles, params) { isSuccess-> + Timber.tag(TAG).d("uploadMultipleImages: ${isSuccess}") + subList.filter { it.imageFile!=null }.forEach { it.uploadSuccess = isSuccess } + +// val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() } +// runOnUiThread { +// binding.btnUploadImage.text = "待上传图片${count}张" +// if (count == 0) { +// Loading.dismiss() +// } +// } + } + } + } + + private fun vectorThread(block:()-> Unit) { settingActivity?.showWaitingDialog("加载中……") Thread { foodCollectionList - .filter { it.bitmap != null } +// .filter { it.bitmap != null } + .filter { it.imageVector != null } .forEachIndexed { index, it -> - image2VectorTask(it, index) + image2VectorTask(imageVector = it.imageVector!!, index) } activity?.runOnUiThread { binding.root.postDelayed({ @@ -212,25 +268,24 @@ class CollectFragment : BaseFragment() { } } - private fun image2VectorTask(item: FoodCollectionBean, position: Int) { + private fun image2VectorTask(imageVector: FloatArray, position: Int) { initBox() - val imageVector = FoodModule.bitmap2FloatArray(item.bitmap!!) - -// val base64Str = FloatBase64Utils.floatArrayToBase64(imageVector) -// Timber.tag("mzf1").e(base64Str) -//// viewModel.postImageData( -//// context, -//// foodId = selectedFoodId.toString(), -//// foodName = selectedFoodName.toString(), -//// foodVector = base64Str, -//// uri = item.imageUri!! -//// ) +// val imageVector = FoodModule.bitmap2FloatArray(item.bitmap!!) +// +//// val base64Str = FloatBase64Utils.floatArrayToBase64(imageVector) +//// Timber.tag("mzf1").e(base64Str) +////// viewModel.postImageData( +////// context, +////// foodId = selectedFoodId.toString(), +////// foodName = selectedFoodName.toString(), +////// foodVector = base64Str, +////// uri = item.imageUri!! +////// ) box?.put(Food(name = checkedItem!!.foodName, foodIdx = 0, foodVector = imageVector)) foodCollectionList[position].let { - it.imageVector = imageVector +// it.imageVector = imageVector it.isFinish = true } - activity?.runOnUiThread { collectionAdapter.notifyItemChanged(position) } diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt index bb2d57e..d77fc6a 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt @@ -33,14 +33,24 @@ class CashPayFragment : BaseFragment() { override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) if (hidden) { - binding.root.postDelayed({ - presentation?.dismiss() - }, 500) + delayDismiss() return } showSubScreen() } + override fun onDestroy() { + delayDismiss() + super.onDestroy() + } + + private fun delayDismiss() { + presentation?.dismiss() + //binding.root.postDelayed({ + // presentation?.dismiss() + //}, 100) + } + private fun showSubScreen() { // 查找副屏(通常索引为1) if (displays.size > 1) { diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt index a58290b..ab9b2a4 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt @@ -29,14 +29,24 @@ class FacePayFragment : BaseFragment() { override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) if (hidden) { - binding.root.postDelayed({ - presentation?.dismiss() - }, 500) + delayDismiss() return } showSubScreen() } + override fun onDestroy() { + delayDismiss() + super.onDestroy() + } + + private fun delayDismiss() { + presentation?.dismiss() + //binding.root.postDelayed({ + // presentation?.dismiss() + //}, 100) + } + fun loadBitmap(frame: Bitmap) { binding.ivFaceImage.setImageBitmap(frame) } diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt index 077901a..eefcadc 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt @@ -29,14 +29,24 @@ class NumberPayFragment: BaseFragment() { override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) if (hidden) { - binding.root.postDelayed({ - presentation?.dismiss() - }, 500) + delayDismiss() return } showSubScreen() } + override fun onDestroy() { + delayDismiss() + super.onDestroy() + } + + private fun delayDismiss() { + presentation?.dismiss() + //binding.root.postDelayed({ + // presentation?.dismiss() + //}, 100) + } + private fun showSubScreen() { // 查找副屏(通常索引为1) if (displays.size > 1) { diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt index 22abe12..a583051 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt @@ -25,6 +25,8 @@ class ScanQrCodePayFragment: BaseFragment() { private var payAmount: String? = null private var payQrCodePic: Any? = null var presentation: ScanQrCodePayPresentation?=null + private var countDownJob: Job? = null + override fun inflateViewBinding(): FragmentScanQrcodePayBinding { return FragmentScanQrcodePayBinding.inflate(layoutInflater) } @@ -47,14 +49,25 @@ class ScanQrCodePayFragment: BaseFragment() { override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) if (hidden) { - binding.root.postDelayed({ - presentation?.dismiss() - }, 500) + delayDismiss() return } showSubScreen() } + override fun onDestroy() { + delayDismiss() + countDownJob?.cancel() // 自动取消订阅,防止内存泄漏 + super.onDestroy() + } + + private fun delayDismiss() { + presentation?.dismiss() + //binding.root.postDelayed({ + // presentation?.dismiss() + //}, 100) + } + private fun showSubScreen() { // 查找副屏(通常索引为1) if (displays.size > 1) { @@ -90,9 +103,4 @@ class ScanQrCodePayFragment: BaseFragment() { } ) } - private var countDownJob: Job? = null - override fun onDestroy() { - super.onDestroy() - countDownJob?.cancel() // 自动取消订阅,防止内存泄漏 - } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodAdapter.kt b/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodAdapter.kt index fe24e3b..ab6dc01 100644 --- a/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodAdapter.kt +++ b/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodAdapter.kt @@ -10,11 +10,11 @@ //import com.sw.dualscreen.R //import com.sw.dualscreen.databinding.ListItemCollectedDataBinding //import com.sw.dualscreen.databinding.ListItemFoodCollectionBinding -//import com.sw.dualscreen.objbox.CollectedFoodBean +//import com.sw.dualscreen.objbox.CollectedFoodInfo //import com.sw.dualscreen.objbox.FoodCollectionBean // -//class CollectedFoodAdapter (var list: MutableList) : -// BaseQuickAdapter(list) { +//class CollectedFoodAdapter (var list: MutableList) : +// BaseQuickAdapter(list) { // // inner class VH(var binding: ListItemCollectedDataBinding) : QuickViewHolder(binding.root) // @@ -24,7 +24,7 @@ // return VH(binding) // } // -// override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodBean?) { +// override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodInfo?) { // holder.binding.tvFoodName.text = item?.foodName // holder.binding.divider.run { // visibility = if (position == list.size - 1) View.GONE else View.VISIBLE diff --git a/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodNewAdapter.kt b/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodNewAdapter.kt index 11f291f..a39a4a9 100644 --- a/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodNewAdapter.kt +++ b/app/src/main/java/com/sw/dualscreen/adapter/CollectedFoodNewAdapter.kt @@ -6,10 +6,10 @@ import android.view.ViewGroup import com.chad.library.adapter4.BaseQuickAdapter import com.chad.library.adapter4.viewholder.QuickViewHolder import com.sw.dualscreen.databinding.ListItemCollectedFoodBinding -import com.sw.dualscreen.objbox.CollectedFoodBean +import com.sw.dualscreen.objbox.CollectedFoodInfo -class CollectedFoodNewAdapter(var list: MutableList) : - BaseQuickAdapter(list) { +class CollectedFoodNewAdapter(var list: MutableList) : + BaseQuickAdapter(list) { inner class VH(var binding: ListItemCollectedFoodBinding) : QuickViewHolder(binding.root) @@ -19,9 +19,9 @@ class CollectedFoodNewAdapter(var list: MutableList) : return VH(binding) } - override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodBean?) { + override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodInfo?) { holder.binding.tvFoodName.text = item?.foodName - holder.binding.tvCollectedNum.text = "已采集${item?.count}" + holder.binding.tvCollectedNum.text = "已采集${item?.foodCount}" } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/adapter/SearchFoodAdapter.kt b/app/src/main/java/com/sw/dualscreen/adapter/SearchFoodAdapter.kt index bc08783..9fe3f48 100644 --- a/app/src/main/java/com/sw/dualscreen/adapter/SearchFoodAdapter.kt +++ b/app/src/main/java/com/sw/dualscreen/adapter/SearchFoodAdapter.kt @@ -26,7 +26,7 @@ class SearchFoodAdapter(var list: MutableList) : text = item.foodName } else { val score = (item.score / 100.0).format2String(2) - text = item.foodName + if (item.score != 0) "-${score}%" else "" + text = item.foodName + (if (item.score != 0) "-${score}%" else "") } isChecked = item.isChecked } diff --git a/app/src/main/java/com/sw/dualscreen/model/response/ApiResponse.kt b/app/src/main/java/com/sw/dualscreen/model/response/ApiResponse.kt index dd189f6..10a7add 100644 --- a/app/src/main/java/com/sw/dualscreen/model/response/ApiResponse.kt +++ b/app/src/main/java/com/sw/dualscreen/model/response/ApiResponse.kt @@ -1,17 +1,16 @@ package com.sw.dualscreen.model.response data class ApiResponse( - val code: Int? = 0, - val message: String? = "", - val result: T? = null, - val success: Boolean? = false, - val timestamp: Long? = 0 + val code: String, + val msg: String? = "", + val data: T? = null ) { - fun isSuccess(): Boolean { - return success == true - } + fun isSuccess(): Boolean = ("00000" == code) + + val result: T? + get() = data + val message: String? + get() = msg } - - 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 new file mode 100644 index 0000000..d50dab9 --- /dev/null +++ b/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt @@ -0,0 +1,5 @@ +package com.sw.dualscreen.model.response + +data class FoodSearchReq( + var nameList:List +) \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/model/response/DinnerTypeInfo.kt b/app/src/main/java/com/sw/dualscreen/model/response/DinnerTypeInfo.kt index 152378b..81a1ed6 100644 --- a/app/src/main/java/com/sw/dualscreen/model/response/DinnerTypeInfo.kt +++ b/app/src/main/java/com/sw/dualscreen/model/response/DinnerTypeInfo.kt @@ -1,42 +1,47 @@ package com.sw.dualscreen.model.response - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class DinnerTypeInfo( - @SerializedName("dinnerType") - val dinnerType: DinnerType? = DinnerType() -) : Parcelable { - @Parcelize - data class DinnerType( - @SerializedName("createBy") - val createBy: String? = "", - @SerializedName("createTime") - val createTime: String? = "", - @SerializedName("delFlag") - val delFlag: Int? = 0, - @SerializedName("dinnerType") - val dinnerType: String? = "", - @SerializedName("endTime") - val endTime: String? = "", - @SerializedName("id") - val id: Int? = 0, - @SerializedName("isSync") - val isSync: Int? = 0, - @SerializedName("isSyncCopy") - val isSyncCopy: Int? = 0, - @SerializedName("restId") - val restId: String? = "", - @SerializedName("startTime") - val startTime: String? = "", - @SerializedName("sysOrgCode") - val sysOrgCode: String? = "", - @SerializedName("updateBy") - val updateBy: String? = "", - @SerializedName("updateTime") - val updateTime: String? = "" - ) : Parcelable -} \ No newline at end of file +//{"id":"1992804086323437569","dinnerType":"晚餐","chargeType":1,"fixedAmount":3.0000} +data class DinnerType( + val id: String? = "", + //餐次 + val dinnerType: String? = "", + //餐次收费模式(0称重,1固定,2不收费) + val chargeType: Int = 0, + //固定收费(元) 仅charge_type = 1 时 + val fixedAmount: Double?=null +) +//@Parcelize +//data class DinnerTypeInfo( +// @SerializedName("dinnerType") +// val dinnerType: DinnerType? = DinnerType() +//) : Parcelable +// +//@Parcelize +//data class DinnerType( +// @SerializedName("createBy") +// val createBy: String? = "", +// @SerializedName("createTime") +// val createTime: String? = "", +// @SerializedName("delFlag") +// val delFlag: Int? = 0, +// @SerializedName("dinnerType") +// val dinnerType: String? = "", +// @SerializedName("endTime") +// val endTime: String? = "", +// @SerializedName("id") +// val id: Int? = 0, +// @SerializedName("isSync") +// val isSync: Int? = 0, +// @SerializedName("isSyncCopy") +// val isSyncCopy: Int? = 0, +// @SerializedName("restId") +// val restId: String? = "", +// @SerializedName("startTime") +// val startTime: String? = "", +// @SerializedName("sysOrgCode") +// val sysOrgCode: String? = "", +// @SerializedName("updateBy") +// val updateBy: String? = "", +// @SerializedName("updateTime") +// val updateTime: String? = "" +//) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/model/response/EquipmentInfo.kt b/app/src/main/java/com/sw/dualscreen/model/response/EquipmentInfo.kt index e017cf3..59b54a7 100644 --- a/app/src/main/java/com/sw/dualscreen/model/response/EquipmentInfo.kt +++ b/app/src/main/java/com/sw/dualscreen/model/response/EquipmentInfo.kt @@ -12,11 +12,11 @@ data class EquipmentInfo( @SerializedName("appPackageUrl") val appPackageUrl: String? = "", @SerializedName("arcsoftActiveKey") - val arcsoftActiveKey: String? = "", + var arcsoftActiveKey: String? = "", @SerializedName("arcsoftAppId") - val arcsoftAppId: String? = "", + var arcsoftAppId: String? = "", @SerializedName("arcsoftSdkKey") - val arcsoftSdkKey: String? = "", + var arcsoftSdkKey: String? = "", @SerializedName("arrayCross") val arrayCross: Int? = 0, @SerializedName("arrayMode") @@ -24,9 +24,9 @@ data class EquipmentInfo( @SerializedName("arrayVertical") val arrayVertical: Int? = 0, @SerializedName("canteenId") - val canteenId: String? = "", + var canteenId: String? = "", @SerializedName("canteenName") - val canteenName: String? = "", + var canteenName: String? = "", @SerializedName("clientServerIp") val clientServerIp: String? = "", @SerializedName("createBy") diff --git a/app/src/main/java/com/sw/dualscreen/model/response/FoodInfo.kt b/app/src/main/java/com/sw/dualscreen/model/response/FoodInfo.kt index 0f1fc7a..58d4c74 100644 --- a/app/src/main/java/com/sw/dualscreen/model/response/FoodInfo.kt +++ b/app/src/main/java/com/sw/dualscreen/model/response/FoodInfo.kt @@ -1,6 +1,5 @@ package com.sw.dualscreen.model.response - import android.net.Uri import android.os.Parcelable import android.text.TextUtils @@ -12,292 +11,296 @@ import kotlinx.parcelize.Parcelize */ @Parcelize data class FoodInfo( - @SerializedName("foodLabel") - val foodLabel: String? = "", - @SerializedName("foodName") - val foodName: String? = "", - @SerializedName("foodTypeAndRealIntakeVoList") - val foodTypeAndRealIntakeVoList: List? = listOf(), - /** - * 食物id - */ - @SerializedName("id") - val id: String? = "", - @SerializedName("imgUrl") - var imgUrl: String? = "", - /** - * 拍照结果 - */ + //菜品id + val foodId:String, + //菜品名称 + val foodName:String? = null, + //能量 + val calorie:String? = null, + //蛋白质 + val protein:String? = null, + //脂肪 + val fat:String? = null, + //碳水化合物 + val carbohydrate:String? = null, + //规格售卖价格(元) + val specPrice:String? = null, + //VIP售卖价(元) + val vipPrice:String? = null, + var score: Int = 0, + var isChecked: Boolean = false, var photoUri: Uri? = null, + var imgUrl: String? = "", + +// @SerializedName("foodTypeAndRealIntakeVoList") +// val foodTypeAndRealIntakeVoList: List? = listOf(), @SerializedName("stFoodInfoMaterial") val stFoodInfoMaterial: StFoodInfoMaterial? = StFoodInfoMaterial(), - @SerializedName("stFoodInfoPagoda") - val stFoodInfoPagoda: StFoodInfoPagoda? = StFoodInfoPagoda(), +// @SerializedName("stFoodInfoPagoda") +// val stFoodInfoPagoda: StFoodInfoPagoda? = StFoodInfoPagoda(), @SerializedName("stFoodInfoPagodaAPPVO") val stFoodInfoPagodaAPPVO: StFoodInfoPagodaAPPVO? = StFoodInfoPagodaAPPVO(), - @SerializedName("stFoodInfoSetting") - val stFoodInfoSetting: StFoodInfoSetting? = StFoodInfoSetting(), - @SerializedName("stFoodInfoSpecificationList") - val stFoodInfoSpecificationList: List? = listOf(), - var score: Int = 0, - var isChecked: Boolean = false +// @SerializedName("stFoodInfoSetting") +// val stFoodInfoSetting: StFoodInfoSetting? = StFoodInfoSetting(), +// @SerializedName("stFoodInfoSpecificationList") +// val stFoodInfoSpecificationList: List? = listOf(), +) : Parcelable + +//@Parcelize +//data class FoodTypeAndRealIntakeVo( +// @SerializedName("childMaterClassName") +// val childMaterClassName: String? = "", +// @SerializedName("foodId") +// val foodId: String? = "", +// @SerializedName("goodsId") +// val goodsId: String? = "", +// @SerializedName("goodsName") +// val goodsName: String? = "", +// @SerializedName("materClassName") +// val materClassName: String? = "", +// @SerializedName("materId") +// val materId: String? = "", +// @SerializedName("materialType") +// val materialType: String? = "", +// @SerializedName("realityIntake") +// val realityIntake: String? = "" +//) : Parcelable + +@Parcelize +data class StFoodInfoMaterial( + @SerializedName("ash") + val ash: Double? = 0.0, + @SerializedName("avitE") + val avitE: Double? = 0.0, + @SerializedName("ca") + val ca: Double? = 0.0, + @SerializedName("cho") + val cho: Double? = 0.0, + @SerializedName("cholesterol") + val cholesterol: Double? = 0.0, + @SerializedName("cu") + val cu: Double? = 0.0, + @SerializedName("delFlag") + val delFlag: String? = "", + @SerializedName("dietFiber") + val dietFiber: Double? = 0.0, + @SerializedName("elementI") + val elementI: Double? = 0.0, + @SerializedName("elementK") + val elementK: String? = "", + @SerializedName("elementP") + val elementP: String? = "", + @SerializedName("energyKcal") + val energyKcal: Double? = 0.0, + @SerializedName("energyKj") + val energyKj: Double? = 0.0, + @SerializedName("fat") + val fat: Double? = 0.0, + @SerializedName("fe") + val fe: Double? = 0.0, + @SerializedName("folate") + val folate: Double? = 0.0, + @SerializedName("foodId") + val foodId: String? = "", + @SerializedName("foodWeight") + val foodWeight: String? = "", + @SerializedName("historyStatus") + val historyStatus: String? = "", + @SerializedName("id") + val id: String? = "", + @SerializedName("isSync") + val isSync: String? = "", + @SerializedName("isSyncCopy") + val isSyncCopy: String? = "", + @SerializedName("mg") + val mg: Double? = 0.0, + @SerializedName("mn") + val mn: Double? = 0.0, + @SerializedName("na") + val na: Double? = 0.0, + @SerializedName("naicin") + val naicin: Double? = 0.0, + @SerializedName("protein") + val protein: Double? = 0.0, + @SerializedName("retionl") + val retionl: Double? = 0.0, + @SerializedName("riboflavin") + val riboflavin: Double? = 0.0, + @SerializedName("se") + val se: Double? = 0.0, + @SerializedName("thiamin") + val thiamin: Double? = 0.0, + @SerializedName("totCarotene") + val totCarotene: Double? = 0.0, + @SerializedName("vitA") + val vitA: Double? = 0.0, + @SerializedName("vitB12") + val vitB12: Double? = 0.0, + @SerializedName("vitB6") + val vitB6: Double? = 0.0, + @SerializedName("vitC") + val vitC: Double? = 0.0, + @SerializedName("vitE") + val vitE: Double? = 0.0, + @SerializedName("water") + val water: Double? = 0.0, + @SerializedName("zn") + val zn: Double? = 0.0 +) : Parcelable + +//@Parcelize +//data class StFoodInfoPagoda( +// @SerializedName("aquatic") +// val aquatic: String? = "", +// @SerializedName("birds") +// val birds: String? = "", +// @SerializedName("delFlag") +// val delFlag: String? = "", +// @SerializedName("egg") +// val egg: String? = "", +// @SerializedName("foodId") +// val foodId: String? = "", +// @SerializedName("fruits") +// val fruits: String? = "", +// @SerializedName("grain") +// val grain: String? = "", +// @SerializedName("id") +// val id: String? = "", +// @SerializedName("isSync") +// val isSync: String? = "", +// @SerializedName("isSyncCopy") +// val isSyncCopy: String? = "", +// @SerializedName("livestock") +// val livestock: String? = "", +// @SerializedName("milk") +// val milk: String? = "", +// @SerializedName("nuts") +// val nuts: String? = "", +// @SerializedName("oil") +// val oil: String? = "", +// @SerializedName("potato") +// val potato: String? = "", +// @SerializedName("salt") +// val salt: String? = "", +// @SerializedName("soya") +// val soya: String? = "", +// @SerializedName("sugar") +// val sugar: String? = "", +// @SerializedName("vegetable") +// val vegetable: String? = "" +//) : Parcelable + +@Parcelize +data class StFoodInfoPagodaAPPVO( + @SerializedName("fruits") + val fruits: String? = "", + @SerializedName("fruitsRecommend") + val fruitsRecommend: String? = "", + @SerializedName("grain") + val grain: String? = "", + @SerializedName("grainRecommend") + val grainRecommend: String? = "", + @SerializedName("meat") + val meat: String? = "", + @SerializedName("meatRecommend") + val meatRecommend: String? = "", + @SerializedName("oil") + val oil: String? = "", + @SerializedName("salt") + val salt: String? = "", + @SerializedName("soya") + val soya: String? = "", + @SerializedName("soyaRecommend") + val soyaRecommend: String? = "", + @SerializedName("sugar") + val sugar: String? = "", + @SerializedName("vegetable") + val vegetable: String? = "", + @SerializedName("vegetableRecommend") + val vegetableRecommend: String? = "" ) : Parcelable { - @Parcelize - data class FoodTypeAndRealIntakeVo( - @SerializedName("childMaterClassName") - val childMaterClassName: String? = "", - @SerializedName("foodId") - val foodId: String? = "", - @SerializedName("goodsId") - val goodsId: String? = "", - @SerializedName("goodsName") - val goodsName: String? = "", - @SerializedName("materClassName") - val materClassName: String? = "", - @SerializedName("materId") - val materId: String? = "", - @SerializedName("materialType") - val materialType: String? = "", - @SerializedName("realityIntake") - val realityIntake: String? = "" - ) : Parcelable - @Parcelize - data class StFoodInfoMaterial( - @SerializedName("ash") - val ash: Double? = 0.0, - @SerializedName("avitE") - val avitE: Double? = 0.0, - @SerializedName("ca") - val ca: Double? = 0.0, - @SerializedName("cho") - val cho: Double? = 0.0, - @SerializedName("cholesterol") - val cholesterol: Double? = 0.0, - @SerializedName("cu") - val cu: Double? = 0.0, - @SerializedName("delFlag") - val delFlag: String? = "", - @SerializedName("dietFiber") - val dietFiber: Double? = 0.0, - @SerializedName("elementI") - val elementI: Double? = 0.0, - @SerializedName("elementK") - val elementK: String? = "", - @SerializedName("elementP") - val elementP: String? = "", - @SerializedName("energyKcal") - val energyKcal: Double? = 0.0, - @SerializedName("energyKj") - val energyKj: Double? = 0.0, - @SerializedName("fat") - val fat: Double? = 0.0, - @SerializedName("fe") - val fe: Double? = 0.0, - @SerializedName("folate") - val folate: Double? = 0.0, - @SerializedName("foodId") - val foodId: String? = "", - @SerializedName("foodWeight") - val foodWeight: String? = "", - @SerializedName("historyStatus") - val historyStatus: String? = "", - @SerializedName("id") - val id: String? = "", - @SerializedName("isSync") - val isSync: String? = "", - @SerializedName("isSyncCopy") - val isSyncCopy: String? = "", - @SerializedName("mg") - val mg: Double? = 0.0, - @SerializedName("mn") - val mn: Double? = 0.0, - @SerializedName("na") - val na: Double? = 0.0, - @SerializedName("naicin") - val naicin: Double? = 0.0, - @SerializedName("protein") - val protein: Double? = 0.0, - @SerializedName("retionl") - val retionl: Double? = 0.0, - @SerializedName("riboflavin") - val riboflavin: Double? = 0.0, - @SerializedName("se") - val se: Double? = 0.0, - @SerializedName("thiamin") - val thiamin: Double? = 0.0, - @SerializedName("totCarotene") - val totCarotene: Double? = 0.0, - @SerializedName("vitA") - val vitA: Double? = 0.0, - @SerializedName("vitB12") - val vitB12: Double? = 0.0, - @SerializedName("vitB6") - val vitB6: Double? = 0.0, - @SerializedName("vitC") - val vitC: Double? = 0.0, - @SerializedName("vitE") - val vitE: Double? = 0.0, - @SerializedName("water") - val water: Double? = 0.0, - @SerializedName("zn") - val zn: Double? = 0.0 - ) : Parcelable + fun fruitsValue(): Double = + if (TextUtils.isEmpty(fruits)) + 0.0 + else fruits!!.toDouble() - @Parcelize - data class StFoodInfoPagoda( - @SerializedName("aquatic") - val aquatic: String? = "", - @SerializedName("birds") - val birds: String? = "", - @SerializedName("delFlag") - val delFlag: String? = "", - @SerializedName("egg") - val egg: String? = "", - @SerializedName("foodId") - val foodId: String? = "", - @SerializedName("fruits") - val fruits: String? = "", - @SerializedName("grain") - val grain: String? = "", - @SerializedName("id") - val id: String? = "", - @SerializedName("isSync") - val isSync: String? = "", - @SerializedName("isSyncCopy") - val isSyncCopy: String? = "", - @SerializedName("livestock") - val livestock: String? = "", - @SerializedName("milk") - val milk: String? = "", - @SerializedName("nuts") - val nuts: String? = "", - @SerializedName("oil") - val oil: String? = "", - @SerializedName("potato") - val potato: String? = "", - @SerializedName("salt") - val salt: String? = "", - @SerializedName("soya") - val soya: String? = "", - @SerializedName("sugar") - val sugar: String? = "", - @SerializedName("vegetable") - val vegetable: String? = "" - ) : Parcelable + fun grainValue(): Double = + if (TextUtils.isEmpty(grain)) + 0.0 + else grain!!.toDouble() - @Parcelize - data class StFoodInfoPagodaAPPVO( - @SerializedName("fruits") - val fruits: String? = "", - @SerializedName("fruitsRecommend") - val fruitsRecommend: String? = "", - @SerializedName("grain") - val grain: String? = "", - @SerializedName("grainRecommend") - val grainRecommend: String? = "", - @SerializedName("meat") - val meat: String? = "", - @SerializedName("meatRecommend") - val meatRecommend: String? = "", - @SerializedName("oil") - val oil: String? = "", - @SerializedName("salt") - val salt: String? = "", - @SerializedName("soya") - val soya: String? = "", - @SerializedName("soyaRecommend") - val soyaRecommend: String? = "", - @SerializedName("sugar") - val sugar: String? = "", - @SerializedName("vegetable") - val vegetable: String? = "", - @SerializedName("vegetableRecommend") - val vegetableRecommend: String? = "" - ) : Parcelable { + fun vegetableValue(): Double = + if (TextUtils.isEmpty(vegetable)) + 0.0 + else vegetable!!.toDouble() - fun fruitsValue(): Double = - if (TextUtils.isEmpty(fruits)) - 0.0 - else fruits!!.toDouble() + fun meatValue(): Double = + if (TextUtils.isEmpty(meat)) + 0.0 + else meat!!.toDouble() +} - fun grainValue(): Double = - if (TextUtils.isEmpty(grain)) - 0.0 - else grain!!.toDouble() +//@Parcelize +//data class StFoodInfoSetting( +// @SerializedName("addFoodWeight") +// val addFoodWeight: String? = "", +// @SerializedName("bowlPlateWeight") +// val bowlPlateWeight: String? = "", +// @SerializedName("delFlag") +// val delFlag: String? = "", +// @SerializedName("foodId") +// val foodId: String? = "", +// @SerializedName("foodStatus") +// val foodStatus: String? = "", +// @SerializedName("id") +// val id: String? = "", +// @SerializedName("inventoryStatus") +// val inventoryStatus: Boolean? = false, +// @SerializedName("isSync") +// val isSync: String? = "", +// @SerializedName("isSyncCopy") +// val isSyncCopy: String? = "", +// @SerializedName("replenishWeight") +// val replenishWeight: String? = "", +// @SerializedName("residueType") +// val residueType: String? = "", +// @SerializedName("tablewareStatus") +// val tablewareStatus: Boolean? = false, +// @SerializedName("tablewareWeight") +// val tablewareWeight: String? = "", +// @SerializedName("warningStatus") +// val warningStatus: String? = "", +// @SerializedName("weighStatus") +// val weighStatus: String? = "", +// @SerializedName("weighUnitId") +// val weighUnitId: String? = "", +// @SerializedName("weighUnitName") +// val weighUnitName: String? = "" +//) : Parcelable - fun vegetableValue(): Double = - if (TextUtils.isEmpty(vegetable)) - 0.0 - else vegetable!!.toDouble() - - fun meatValue(): Double = - if (TextUtils.isEmpty(meat)) - 0.0 - else meat!!.toDouble() - } - - @Parcelize - data class StFoodInfoSetting( - @SerializedName("addFoodWeight") - val addFoodWeight: String? = "", - @SerializedName("bowlPlateWeight") - val bowlPlateWeight: String? = "", - @SerializedName("delFlag") - val delFlag: String? = "", - @SerializedName("foodId") - val foodId: String? = "", - @SerializedName("foodStatus") - val foodStatus: String? = "", - @SerializedName("id") - val id: String? = "", - @SerializedName("inventoryStatus") - val inventoryStatus: Boolean? = false, - @SerializedName("isSync") - val isSync: String? = "", - @SerializedName("isSyncCopy") - val isSyncCopy: String? = "", - @SerializedName("replenishWeight") - val replenishWeight: String? = "", - @SerializedName("residueType") - val residueType: String? = "", - @SerializedName("tablewareStatus") - val tablewareStatus: Boolean? = false, - @SerializedName("tablewareWeight") - val tablewareWeight: String? = "", - @SerializedName("warningStatus") - val warningStatus: String? = "", - @SerializedName("weighStatus") - val weighStatus: String? = "", - @SerializedName("weighUnitId") - val weighUnitId: String? = "", - @SerializedName("weighUnitName") - val weighUnitName: String? = "" - ) : Parcelable - - @Parcelize - data class StFoodInfoSpecification( - @SerializedName("bowlPlateWeight") - val bowlPlateWeight: Double? = 0.0, - @SerializedName("defaultStatus") - val defaultStatus: String? = "", - @SerializedName("delFlag") - val delFlag: String? = "", - @SerializedName("foodId") - val foodId: String? = "", - @SerializedName("id") - val id: String? = "", - @SerializedName("isSync") - val isSync: String? = "", - @SerializedName("isSyncCopy") - val isSyncCopy: String? = "", - @SerializedName("specId") - val specId: String? = "", - @SerializedName("specName") - val specName: String? = "", - @SerializedName("specPrice") - val specPrice: String? = "", - @SerializedName("specWeight") - val specWeight: Double? = 0.0 - ) : Parcelable -} \ No newline at end of file +//@Parcelize +//data class StFoodInfoSpecification( +// @SerializedName("bowlPlateWeight") +// val bowlPlateWeight: Double? = 0.0, +// @SerializedName("defaultStatus") +// val defaultStatus: String? = "", +// @SerializedName("delFlag") +// val delFlag: String? = "", +// @SerializedName("foodId") +// val foodId: String? = "", +// @SerializedName("id") +// val id: String? = "", +// @SerializedName("isSync") +// val isSync: String? = "", +// @SerializedName("isSyncCopy") +// val isSyncCopy: String? = "", +// @SerializedName("specId") +// val specId: String? = "", +// @SerializedName("specName") +// val specName: String? = "", +// @SerializedName("specPrice") +// val specPrice: String? = "", +// @SerializedName("specWeight") +// val specWeight: Double? = 0.0 +//) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/model/response/UserFaceModel.kt b/app/src/main/java/com/sw/dualscreen/model/response/UserFaceModel.kt index 3050bb3..be2d429 100644 --- a/app/src/main/java/com/sw/dualscreen/model/response/UserFaceModel.kt +++ b/app/src/main/java/com/sw/dualscreen/model/response/UserFaceModel.kt @@ -10,14 +10,15 @@ import kotlinx.parcelize.Parcelize */ @Parcelize data class UserFaceModel( - @SerializedName("faceFeature") - val faceFeature: String? = "", - @SerializedName("faceFeatureString") - val faceFeatureString: String? = "", - @SerializedName("faceType") - val faceType: String? = "", - @SerializedName("userFaceId") - val userFaceId: String? = "", - @SerializedName("userId") - val userId: String? = "" +// @SerializedName("faceFeature") +// val faceFeature: String? = "", +// @SerializedName("faceFeatureString") +// val faceFeatureString: String? = "", +// @SerializedName("faceType") +// val faceType: String? = "", +// @SerializedName("userFaceId") +// val userFaceId: String? = "", +// @SerializedName("userId") + val userId: String? = "", + val faceFeatureStr: String? = "" ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt b/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt index 12b6d01..7099c89 100644 --- a/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt +++ b/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt @@ -3,16 +3,16 @@ package com.sw.dualscreen.network.api import com.sw.dualscreen.GlobalData import com.sw.dualscreen.model.request.UserNutritionParam import com.sw.dualscreen.model.response.ApiResponse -import com.sw.dualscreen.model.response.DinnerTypeInfo -import com.sw.dualscreen.model.response.EquipmentInfo +import com.sw.dualscreen.model.response.DinnerType import com.sw.dualscreen.model.response.FoodInfo -import com.sw.dualscreen.model.response.UserFaceInfo +import com.sw.dualscreen.model.response.FoodSearchReq +import com.sw.dualscreen.model.response.UserFaceModel import com.sw.dualscreen.model.response.UserNutritionData +import com.sw.dualscreen.objbox.CollectedFoodInfo import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.http.Body import retrofit2.http.GET -import retrofit2.http.Header import retrofit2.http.Multipart import retrofit2.http.POST import retrofit2.http.Part @@ -25,41 +25,54 @@ interface ApiService { /** * device获取token */ - @GET("sys/getEquipmentToken") - suspend fun getDeviceToken( - @Query("qrcodeId") qrcodeId: String, - @Query("appVersion") appVersion: String = GlobalData.appVersion - ): ApiResponse +// @GET("sys/getEquipmentToken") +// suspend fun getDeviceToken( +// @Query("qrcodeId") qrcodeId: String, +// @Query("appVersion") appVersion: String = GlobalData.appVersion +// ): ApiResponse /** *获取配置信息 */ - @GET("equipment/stEquipment/queryByEquipmentCode") - suspend fun getDeviceInfo( - @Query("equipmentCode") equipmentCode: String, - @Query("appVersion") appVersion: String = GlobalData.appVersion, - @Header("X-Access-Token") token: String - ): ApiResponse +// @GET("equipment/stEquipment/queryByEquipmentCode") +// suspend fun getDeviceInfo( +// @Query("equipmentCode") equipmentCode: String, +// @Query("appVersion") appVersion: String = GlobalData.appVersion, +// @Header("X-Access-Token") token: String +// ): ApiResponse /** * 获取业务服务器token */ - @GET - suspend fun getEquipmentToken( - @Url url: String = "${GlobalData.appBaseUrl}/sys/getEquipmentToken", - @Query("appVersion") appVersion: String = GlobalData.appVersion, - @Query("qrcodeId") qrcodeId: String - ): ApiResponse +// @GET +// suspend fun getEquipmentToken( +// @Url url: String = "${GlobalData.appBaseUrl}/sys/getEquipmentToken", +// @Query("appVersion") appVersion: String = GlobalData.appVersion, +// @Query("qrcodeId") qrcodeId: String +// ): ApiResponse /** * 获取人脸数据 */ - @GET + @POST suspend fun getUserFaceCache( - @Url url: String = "${GlobalData.appBaseUrl}/stapi/cquser/getUserFaceCache/v2", - @Query("appVersion") appVersion: String = GlobalData.appVersion, - @Query("pageIndex") pageIndex: Int - ): ApiResponse +// @Url url: String = "${GlobalData.appBaseUrl}/stapi/cquser/getUserFaceCache/v2", + @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/common/app/faceFeature/list", +// @Query("appVersion") appVersion: String = GlobalData.appVersion, +// @Query("pageIndex") pageIndex: Int + @Body param: Map +// @Query("pageNum") pageNum: Int, +// @Query("pageSize") pageSize: Int + ): ApiResponse> + + /** + * 获取已采集数据列表 + */ + @POST + suspend fun getCollectedFoodList( + @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/boothMachine/app/dishPage", + @Body param: Map + ): ApiResponse> /** @@ -67,11 +80,14 @@ interface ApiService { */ @GET suspend fun getRestInfoFoodsByType( - @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getRestInfoFoodsByType/stall", - @Query("appVersion") appVersion: String = GlobalData.appVersion, - @Query("restId") restId: String, - @Query("type") type: Int, - @Query("foodName") foodName: String, +// @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getRestInfoFoodsByType/stall", +// @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/boothMachine/app/getFoodsByFoodNamePage", + @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/boothMachine/app/getFoodsByFoodNameList", + @Query("name") foodName: String, +// @Query("appVersion") appVersion: String = GlobalData.appVersion, +// @Query("restId") restId: String, +// @Query("type") type: Int, +// @Query("foodName") foodName: String, ): ApiResponse> /** @@ -91,10 +107,11 @@ interface ApiService { */ @GET suspend fun getDinnerType( - @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getCanteenDinnerType", - @Query("appVersion") appVersion: String = GlobalData.appVersion, - @Query("canteenId") restId: String, - ): ApiResponse +// @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getCanteenDinnerType", + @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/boothMachine/app/getRegionRule", +// @Query("appVersion") appVersion: String = GlobalData.appVersion, +// @Query("canteenId") restId: String, + ): ApiResponse /** * 提交就餐数据 @@ -108,11 +125,13 @@ interface ApiService { /** * 获取菜品信息 */ - @GET + @POST suspend fun getFoodInfo( - @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getRestInfoFoodsByType/stall/v2", - @Query("restId") restId: String, - @Query("foodNames") foodName: String, +// @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getRestInfoFoodsByType/stall/v2", + @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/boothMachine/app/goodsList", +// @Query("restId") restId: String, +// @Query("foodNames") foodName: String + @Body req: FoodSearchReq ): ApiResponse> @@ -121,10 +140,11 @@ interface ApiService { */ @Multipart @POST - suspend fun postImageData( - @Url url: String = "http://192.168.1.201:14801/terminal/neglect/dishCollectionVectorData/add", - @PartMap params: Map, - @Part image: MultipartBody.Part? + suspend fun uploadCollectFoodPics( +// @Url url: String = "http://192.168.1.201:14801/terminal/neglect/dishCollectionVectorData/add", + @Url url: String = "http://192.168.1.201:14801/terminal/neglect/boothMachine/app/dishCollectionVectorData/add", + @PartMap params: HashMap, + @Part foodPics: List ): ApiResponse } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/network/interceptor/RequestInterceptor.kt b/app/src/main/java/com/sw/dualscreen/network/interceptor/RequestInterceptor.kt index 0a9ccc3..3fe4848 100644 --- a/app/src/main/java/com/sw/dualscreen/network/interceptor/RequestInterceptor.kt +++ b/app/src/main/java/com/sw/dualscreen/network/interceptor/RequestInterceptor.kt @@ -1,6 +1,7 @@ package com.sw.dualscreen.network.interceptor import android.text.TextUtils +import com.sw.dualscreen.GlobalData import com.sw.dualscreen.GlobalKey import com.sw.dualscreen.utils.SPUtil import com.sw.plate.App @@ -18,7 +19,10 @@ class RequestInterceptor : Interceptor { .header("Content-Type", "application/json") .header("Accept", "application/json") // .header("Authorization", "Bearer ${getToken()}") - .header("X-Access-Token", getToken(originalRequest)) +// .header("X-Access-Token", getToken(originalRequest)) +// .header("X-DEVICE-CODE", "bcf396ed-78f6-3864-9837-7c37c5b2ec41") + .header("X-DEVICE-CODE", GlobalData.deviceId) + .header("authorization", "57ee87183f2a4fa59683ec9ef41c8f5d") val newRequest = requestBuilder.build() diff --git a/app/src/main/java/com/sw/dualscreen/objbox/DataBean.kt b/app/src/main/java/com/sw/dualscreen/objbox/DataBean.kt index 67f36e9..325e06c 100644 --- a/app/src/main/java/com/sw/dualscreen/objbox/DataBean.kt +++ b/app/src/main/java/com/sw/dualscreen/objbox/DataBean.kt @@ -2,6 +2,7 @@ package com.sw.dualscreen.objbox import android.graphics.Bitmap import android.net.Uri +import java.io.File data class FoodClassInfo( var class_names: List, @@ -17,14 +18,20 @@ data class FoodClassInfo( //) data class FoodCollectionBean( - var imageUri: Uri? = null, + var imageFile: File? = null, var bitmap: Bitmap? = null, var imageVector: FloatArray? = null, var isShowCamera: Boolean = false, - var isFinish:Boolean = false + var isFinish:Boolean = false, + var uploadSuccess:Boolean = false ) -data class CollectedFoodBean( - var foodName: String?, - var count: Int = 0 +data class CollectedFoodInfo( + var id: String? = null, + var placeId: String? = null, + var foodId: String? = null, + var foodName: String? = null, + var foodPic: Any? = null, + var foodVector: Any? = null, + var foodCount: Int = 0 ) 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 9e94606..95bba69 100644 --- a/app/src/main/java/com/sw/dualscreen/presentation/MainScreenPresentation.kt +++ b/app/src/main/java/com/sw/dualscreen/presentation/MainScreenPresentation.kt @@ -29,7 +29,7 @@ import com.sw.dualscreen.ext.gone import com.sw.dualscreen.ext.maskName import com.sw.dualscreen.ext.visible import com.sw.dualscreen.model.request.UserNutritionParam -import com.sw.dualscreen.model.response.DinnerTypeInfo +import com.sw.dualscreen.model.response.DinnerType import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.UserNutritionData import com.sw.dualscreen.utils.Debouncer @@ -89,7 +89,7 @@ class MainScreenPresentation( private var detectWeight = 0.0 //识别菜品时的重量 private var lastWeight = 0.0 // 上一次的计算热量结果 private var userNutritionData: UserNutritionData? = null - private var dinnerTypeInfo: DinnerTypeInfo? = null + private var dinnerTypeInfo: DinnerType? = null private val debouncer = Debouncer(500) private var recognitionTime: Long = 0L // 人脸识别时的时间 private var recognitionWeight: Double = 0.0 // 人脸识别时的重量 @@ -228,27 +228,18 @@ class MainScreenPresentation( return } updateFoodInfo(currentFood!!) -// binding.flPreview.visibility = View.VISIBLE -// binding.ivRecImage.visibility = View.VISIBLE -// binding.flFace.visibility = View.INVISIBLE -//// binding.ivFaceBg.visibility = View.GONE -// binding.tvFaceTip.visibility = View.GONE -// -//// binding.tvBottomTip.visibility = View.GONE -// binding.nutritionInclude.clNutritionData.visibility = View.VISIBLE - foodRecSuccess(currentFood!!) } private fun initView() { - binding.ivRecImage.let { - it.outlineProvider = object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) - } - } - it.clipToOutline = true - } +// //binding.ivRecImage.let { +// it.outlineProvider = object : ViewOutlineProvider() { +// override fun getOutline(view: View, outline: Outline) { +// outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) +// } +// } +// it.clipToOutline = true +// } } override fun onDisplayRemoved() { super.onDisplayRemoved() @@ -270,7 +261,7 @@ class MainScreenPresentation( /** * 餐品识别成功,计费模式 */ - fun loadBilledMode(foodInfo: FoodInfo) { + fun loadBilledMode() { binding.calorieInclude.root.visible() binding.nutritionInclude.root.gone() @@ -279,7 +270,7 @@ class MainScreenPresentation( binding.tvFaceTip.gone() binding.tvFoodRecPrompt.gone() binding.llPriceInfo.visible() - binding.ivRecImage.gone() + //binding.ivRecImage.gone() //updateFoodInfo(foodInfo) @@ -291,7 +282,7 @@ class MainScreenPresentation( /** * 餐品识别成功,不计费模式 */ - fun loadUnbilledMode(foodInfo: FoodInfo) { + fun loadUnbilledMode() { binding.calorieInclude.root.gone() binding.nutritionInclude.root.visible() @@ -300,7 +291,7 @@ class MainScreenPresentation( binding.tvFaceTip.gone() binding.tvFoodRecPrompt.gone() binding.llPriceInfo.gone() - binding.ivRecImage.gone() + //binding.ivRecImage.gone() //updateFoodInfo(foodInfo) userNutritionData?.let { @@ -342,10 +333,12 @@ class MainScreenPresentation( binding.tvFoodRecPrompt.visible() binding.flCameraView.visible() binding.ivPreviewImage.visible() - binding.ivRecImage.gone() + //binding.ivRecImage.gone() binding.ivFaceRecMask.gone() binding.tvFaceTip.gone() binding.llPriceInfo.gone() + binding.flFace.gone() + binding.flRecognizeIr.gone() pauseCamera() activity.clearFoodList() @@ -356,10 +349,10 @@ class MainScreenPresentation( val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) if (mode == 0) { //计费 - loadBilledMode(foodInfo) + loadBilledMode() } else { //不计费 - loadUnbilledMode(foodInfo) + loadUnbilledMode() } } @@ -377,13 +370,14 @@ class MainScreenPresentation( binding.tvFoodName.text = foodInfo.foodName binding.flFace.visible() + binding.flRecognizeIr.visible() binding.flCameraView.visible() binding.ivFaceRecMask.visible() binding.tvFaceTip.visible() binding.tvFoodRecPrompt.visible() binding.llPriceInfo.gone() - binding.ivRecImage.gone() + //binding.ivRecImage.gone() binding.ivPreviewImage.gone() dinnerTypeInfo = null @@ -413,22 +407,22 @@ class MainScreenPresentation( private fun updateFoodInfo(foodInfo: FoodInfo) { binding.tvFoodName.text = foodInfo.foodName binding.ivPreviewImage.gone() - binding.ivRecImage.visible() - if (foodInfo.photoUri != null) { - GlideUtils.loadRoundCornerImage( - context, - url = foodInfo.photoUri, - imageView = binding.ivRecImage, - radius = 12 - ) - } else { - GlideUtils.loadRoundCornerImage( - context, - url = foodInfo.imgUrl, - imageView = binding.ivRecImage, - radius = 12 - ) - } + //binding.ivRecImage.visible() +// if (foodInfo.photoUri != null) { +// GlideUtils.loadRoundCornerImage( +// context, +// url = foodInfo.photoUri, +// imageView = //binding.ivRecImage, +// radius = 12 +// ) +// } else { +// GlideUtils.loadRoundCornerImage( +// context, +// url = foodInfo.imgUrl, +// imageView = //binding.ivRecImage, +// radius = 12 +// ) +// } } private fun calculateNutrition(weight1: Double) { @@ -436,7 +430,7 @@ class MainScreenPresentation( if (weight < 0) weight = 0.0 debouncer.debounce { Timber.tag(TAG).d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight") - val dinnerType = dinnerTypeInfo!!.dinnerType!!.dinnerType!! + val dinnerType = dinnerTypeInfo!!.dinnerType!! Timber.tag(TAG).d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}") val calcResultInfo = UserNutritionUtils.calculateNutrition( currentFood!!, @@ -638,7 +632,7 @@ class MainScreenPresentation( } userViewModel.getUserNutritionData( userId = userId, - foodId = currentFood!!.id!! + foodId = currentFood!!.foodId!! ) }) @@ -953,7 +947,7 @@ class MainScreenPresentation( } val userNutritionParam = UserNutritionParam( userId = userNutritionData?.userId!!, - foodId = currentFood?.id!!, + foodId = currentFood?.foodId !!, faceTime = recognitionTime, faceEndTime = System.currentTimeMillis(), eatWeight = eatWeight,//lastWeight diff --git a/app/src/main/java/com/sw/dualscreen/presentation/SecondaryScreenPresentation.kt b/app/src/main/java/com/sw/dualscreen/presentation/SecondaryScreenPresentation.kt index 00f625e..208334f 100644 --- a/app/src/main/java/com/sw/dualscreen/presentation/SecondaryScreenPresentation.kt +++ b/app/src/main/java/com/sw/dualscreen/presentation/SecondaryScreenPresentation.kt @@ -1,886 +1,886 @@ -package com.sw.dualscreen.presentation - -import android.Manifest -import android.app.Presentation -import android.content.Context -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.util.DisplayMetrics -import android.view.Display -import android.view.View -import android.view.ViewGroup -import android.view.ViewOutlineProvider -import android.view.ViewTreeObserver -import androidx.annotation.RequiresApi -import androidx.core.content.ContextCompat -import androidx.lifecycle.Observer -import androidx.lifecycle.lifecycleScope -import com.arcsoft.face.ErrorInfo -import com.sw.dualscreen.R -import com.sw.dualscreen.activity.MainActivity -import com.sw.dualscreen.databinding.ItemUserNutritionBinding -import com.sw.dualscreen.databinding.PresentationSecondaryScreenBinding -import com.sw.dualscreen.ext.dp -import com.sw.dualscreen.ext.format2String -import com.sw.dualscreen.ext.maskName -import com.sw.dualscreen.model.request.UserNutritionParam -import com.sw.dualscreen.model.response.DinnerTypeInfo -import com.sw.dualscreen.model.response.FoodInfo -import com.sw.dualscreen.model.response.UserNutritionData -import com.sw.dualscreen.utils.Debouncer -import com.sw.dualscreen.utils.GlideUtils -import com.sw.dualscreen.viewmodel.UserViewModel -import com.sw.plate.utils.LightManager -import com.sw.plate.utils.ToastUtils -import com.sw.plate.utils.arcface.ConfigUtil -import com.sw.plate.utils.arcface.ErrorCodeUtil -import com.sw.plate.utils.arcface.FaceRectTransformer -import com.sw.plate.utils.arcface.FaceRectView -import com.sw.plate.utils.arcface.FaceRectView.DrawInfo -import com.sw.plate.utils.arcface.PreviewConfig -import com.sw.plate.utils.arcface.camera.CameraListener -import com.sw.plate.utils.arcface.camera.DualCameraHelper -import com.sw.plate.utils.arcface.face.constants.LivenessType -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 kotlinx.coroutines.flow.drop -import kotlinx.coroutines.launch -import timber.log.Timber - -/** - * 用户屏幕 - */ -class SecondaryScreenPresentation( - val activity: MainActivity, - context: Context, - display: Display, - val viewModel: UserViewModel, - private val onDismissListener: () -> Unit = {}, - val recognizeViewModel: RecognizeViewModel -) : Presentation(context, display), ViewTreeObserver.OnGlobalLayoutListener { - private lateinit var binding: PresentationSecondaryScreenBinding - - // 当前食物信息 - private var currentFood: FoodInfo? = null - private var userNutritionData: UserNutritionData? = null - private var dinnerTypeInfo: DinnerTypeInfo? = null - private lateinit var itemUserNutritionBinding: ItemUserNutritionBinding - private lateinit var stepChangeCallback: (Int) -> Unit - - - private var detectWeight = 0.0 //识别菜品时的重量 - private var lastWeight = 0.0 // 上一次的计算热量结果 - private val debouncer = Debouncer(500) - private var recognitionTime: Long = 0L // 人脸识别时的时间 - private var recognitionWeight: Double = 0.0 // 人脸识别时的重量 - private var lastFaceTrackId: Int = -1 // 上一次的人脸信息 - var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐 - - // 当前步骤 - var currentStep: Int = 0 - - private var isGoStep1 = false;//防止持续调用 - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - binding = PresentationSecondaryScreenBinding.inflate(layoutInflater) - setContentView(binding.root) - window?.setBackgroundDrawableResource(android.R.color.transparent) - initView() - setupArcCamera() - registerDataChange() - } - - private fun registerDataChange() { - activity.lifecycleScope.launch { - viewModel.loadFaceResult.collect { needUpdate -> - if (needUpdate) { - recognizeViewModel.refreshFaceList() - } - } - } - activity.lifecycleScope.launch { - viewModel.nutritionData.collect { - Timber.d("registerDataChange nutritionData = $it") - userNutritionData = it - if (it == null) return@collect - step3() - itemUserNutritionBinding.tvUserName.text = it.userName.maskName() - itemUserNutritionBinding.tvRecommendHeat.text = - "推荐热量:${it.recommendMin}-${it.recommendMax}" - - updateWeight(lastWeight / 1000) - } - } - activity.lifecycleScope.launch { - viewModel.dinnerTypeInfo.drop(1).collect { - Timber.d("registerDataChange dinnerTypeInfo = $it") - dinnerTypeInfo = it - } - } - } - - private fun initView() { - binding.ivImg.outlineProvider = object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) - } - } - binding.ivImg.clipToOutline = true - itemUserNutritionBinding = binding.includeUserNutrition - } - - override fun onDisplayRemoved() { - super.onDisplayRemoved() - onDismissListener() - } - - fun updateImage(bitmap: Bitmap) { - activity.runOnUiThread { - binding.ivImg.setImageBitmap(bitmap) - } - } - - /** - * 启用虹软人脸失败 - */ - private fun setupArcCamera() { - initArcViewModel() - initArcView() - openRectInfoDraw = true - } - - /** - * 用户1 显示相机预览 - */ - fun step1() { - Timber.d("step1") - currentStep = 1 - LightManager.closeGreenLight() - LightManager.closeRedLight() - //回复上一次的设置 -// lastWeight = 0.0 - dinnerTypeInfo = null - currentFood = null - userNutritionData = null - recognitionWeight = 0.0 - - stepChangeCallback(currentStep) - binding.tvFoodName.text = "菜品识别中" - binding.ivFaceBg.visibility = View.GONE - binding.flPreview.visibility = View.VISIBLE - binding.ivImg.visibility = View.VISIBLE - binding.flFace.visibility = View.INVISIBLE - binding.tvFaceTip.visibility = View.GONE - pauseCamera() - binding.tvBottomTip.visibility = View.VISIBLE - itemUserNutritionBinding.clNutritionData.visibility = View.GONE - - activity.clearFoodList() - } - - /** - * 显示人脸识别 - */ - fun step2(foodInfo: FoodInfo) { - isGoStep1 = true - Timber.d("step2") - currentStep = 2 - LightManager.closeRedLight() -// LightManager.openGreenLight() - dinnerTypeInfo = null - userNutritionData = null - recognitionWeight = 0.0 - - stepChangeCallback(currentStep) - currentFood = foodInfo - viewModel.getDinnerType() - resumeCamera() - binding.tvFoodName.text = foodInfo.foodName - binding.ivImg.visibility = View.GONE - - binding.flPreview.visibility = View.GONE - -// binding.flFace.visibility = View.VISIBLE - binding.flFace.post { - binding.flFace.visibility = View.VISIBLE - } - binding.ivFaceBg.visibility = View.VISIBLE - binding.tvFaceTip.visibility = View.VISIBLE - binding.tvBottomTip.visibility = View.VISIBLE - itemUserNutritionBinding.clNutritionData.visibility = View.GONE - } - - fun updateFood(foodInfo: FoodInfo?) { - Timber.d("updateFood") - currentFood = foodInfo - if (foodInfo != null) { - if (currentStep == 1) { - step2(foodInfo) - } else { - updateFoodInfo(foodInfo) - } - } - } - - /** - * 显示识别出的菜品信息 - */ - fun step3() { - Timber.d("step3") - LightManager.closeRedLight() - LightManager.openGreenLight() - currentStep = 3 - stepChangeCallback(currentStep) - if (currentFood == null) { - ToastUtils.showToast("选中物品为空3") - return - } - updateFoodInfo(currentFood!!) - binding.flPreview.visibility = View.VISIBLE - binding.ivImg.visibility = View.VISIBLE - binding.flFace.visibility = View.INVISIBLE - binding.ivFaceBg.visibility = View.GONE - binding.tvFaceTip.visibility = View.GONE - - binding.tvBottomTip.visibility = View.GONE - itemUserNutritionBinding.clNutritionData.visibility = View.VISIBLE - } - - private fun updateFoodInfo(foodInfo: FoodInfo) { - binding.tvFoodName.text = foodInfo.foodName - if (foodInfo.photoUri != null) { - GlideUtils.loadRoundCornerImage( - context, - url = foodInfo.photoUri, - imageView = binding.ivImg, - radius = 12 - ) - } else { - GlideUtils.loadRoundCornerImage( - context, - url = foodInfo.imgUrl, - imageView = binding.ivImg, - radius = 12 - ) - } - } - - fun updateWeight(weight: Double) { - lastWeight = weight * 1000 // 将千克转成克 - Timber.d("updateWeight lastWeight = $weight") - if (currentStep == 2 && - lastWeight <= 5 && - isGoStep1 - ) {//人脸识别过程中,秤上物品拿走 - isGoStep1 = false - activity.runOnUiThread { - Timber.e("切回step1") - step1() - } - } - - - if (currentFood == null) { - Timber.e("updateWeight currentFood is null") - return - } - - - if (userNutritionData == null) { - Timber.e("updateWeight userNutritionData is null") - return - } - if (dinnerTypeInfo == null) { - Timber.e("updateWeight dinnerType is null") - return - } - calculateNutrition(recognitionWeight - lastWeight) - } - - fun updateDetectWeight(weight: Double) { - detectWeight = weight * 1000 // 将千克转成克 - } - - /** - * 余量取餐 - */ - fun updateMealPickupMode(mode: Int) { - Timber.d("updateMealPickupMode mode = $mode") - mealPickupMode = mode - step1() - } - - private fun calculateNutrition(weight1: Double) { - var weight = weight1 - if (weight < 0) weight = 0.0 - debouncer.debounce { - Timber.d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight") - val dinnerType = dinnerTypeInfo!!.dinnerType!!.dinnerType!! - Timber.d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}") - val calcResultInfo = UserNutritionUtils.calculateNutrition( - currentFood!!, - userNutritionData!!, - weight, - dinnerType = dinnerType - ) - Timber.d("calculateNutrition calcResultInfo = $calcResultInfo") - val columnMax = UserNutritionUtils.getMaxInt(calcResultInfo) - - activity.runOnUiThread { - val totalKcal = calcResultInfo.totalKcal - val grain = calcResultInfo.grain - val fruits = calcResultInfo.fruits - val meat = calcResultInfo.meat - // 设置热量 - itemUserNutritionBinding.customKcalColumn.setImageDrawable( - true, - totalKcal.max < totalKcal.current - ) - var maxKcal = totalKcal.max - Timber.d("maxKcal = $maxKcal") - // 避免0作为被除数 - if (maxKcal <= 0.0) { - maxKcal = 1.0 - } - Timber.d("maxKcal 1 = $maxKcal") - itemUserNutritionBinding.totalKcalTv.text = totalKcal.current.format2String() - var totalKcalHeight = (totalKcal.current / maxKcal).toFloat() - if (totalKcalHeight == 0F) { - itemUserNutritionBinding.divKcalView.visibility = View.VISIBLE - } else { - itemUserNutritionBinding.divKcalView.visibility = View.GONE - totalKcalHeight += 0.1F - } - itemUserNutritionBinding.customKcalColumn.setCustomHeightPercent( - totalKcalHeight, - true - ) - - // 设置主食 - itemUserNutritionBinding.customFoodColumn.setImageDrawable( - false, - grain.max < grain.current - ) - itemUserNutritionBinding.totalFoodTv.text = grain.current.format2String() - var grainHeight = (grain.current / columnMax).toFloat() - if (grainHeight == 0F) { - itemUserNutritionBinding.divTotalFoodView.visibility = View.VISIBLE - } else { - itemUserNutritionBinding.divTotalFoodView.visibility = View.GONE - grainHeight += 0.1F - } - itemUserNutritionBinding.customFoodColumn.setCustomHeightPercent( - grainHeight, - true - ) - - // 设置果蔬 - itemUserNutritionBinding.customVegetableColumn.setImageDrawable( - false, - fruits.max < fruits.current - ) - itemUserNutritionBinding.totalVegetableTv.text = fruits.current.format2String() - var fruitsHeight = (fruits.current / columnMax).toFloat() - - if (fruitsHeight == 0F) { - itemUserNutritionBinding.divVegetableView.visibility = View.VISIBLE - } else { - itemUserNutritionBinding.divVegetableView.visibility = View.GONE - fruitsHeight += 0.1F - } - itemUserNutritionBinding.customVegetableColumn.setCustomHeightPercent( - fruitsHeight, - true - ) - - // 设置肉蛋 - itemUserNutritionBinding.customMeatColumn.setImageDrawable( - false, - meat.max < meat.current - ) - itemUserNutritionBinding.totalMeatTv.text = meat.current.format2String() - var meatHeight = (meat.current / columnMax).toFloat() - if (meatHeight == 0F) { - itemUserNutritionBinding.divMeatView.visibility = View.VISIBLE - } else { - itemUserNutritionBinding.divMeatView.visibility = View.GONE - meatHeight += 0.1F - } - itemUserNutritionBinding.customMeatColumn.setCustomHeightPercent( - meatHeight, - true - ) - } - } - } - - private fun openCamera() { - Timber.d("openCamera") - if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != - PackageManager.PERMISSION_GRANTED - ) { - ToastUtils.showToast("无摄像头权限") - return - } - try { - val cameraCount = Camera.getNumberOfCameras() - if (cameraCount < 3) { - ToastUtils.showToast("摄像头数量异常") - return - } - recognizeViewModel.init( - PreviewConfig( - 2, 1, 90, 90 - ) - ) - initRgbCamera() - if (DualCameraHelper.hasDualCamera() && livenessType === LivenessType.IR) { - initIrCamera() - } - } catch (e: Exception) { - Timber.e(e, "打开摄像头失败") - } - } - - fun setStepChangeCallback(callback: (Int) -> Unit) { - stepChangeCallback = callback - } - - // 虹软人脸配置 ⬇ - private var isRecognition = false - private var rgbCameraHelper: DualCameraHelper? = null - private var rgbFaceRectTransformer: FaceRectTransformer? = null - private val livenessType = LivenessType.IR - private var openRectInfoDraw = false - - private var irCameraHelper: DualCameraHelper? = null - private var irFaceRectTransformer: FaceRectTransformer? = null - - private fun initArcViewModel() { - - recognizeViewModel.setLiveType(livenessType) - - recognizeViewModel.ftInitCode.observe(activity, Observer { ftInitCode: Int? -> - if (ftInitCode != ErrorInfo.MOK) { - val error: String? = context.getString( - R.string.specific_engine_init_failed, "ftEngine", - ftInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(ftInitCode!!) - ) - Timber.e("ftInitCode observe = $error") - ToastUtils.showToast(error) - } - }) - recognizeViewModel.frInitCode.observe(activity, Observer { frInitCode: Int? -> - if (frInitCode != ErrorInfo.MOK) { - val error: String? = context.getString( - R.string.specific_engine_init_failed, "frEngine", - frInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(frInitCode!!) - ) - Timber.e("frInitCode observe = $error") - ToastUtils.showToast(error) - } - }) - recognizeViewModel.flInitCode.observe(activity, Observer { flInitCode: Int? -> - if (flInitCode != ErrorInfo.MOK) { - val error: String? = context.getString( - R.string.specific_engine_init_failed, "flEngine", - flInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(flInitCode!!) - ) - Timber.e("flInitCode observe = $error") - ToastUtils.showToast(error) - } - }) - - recognizeViewModel.recognizeConfiguration - .observe(activity, Observer { recognizeConfiguration: RecognizeConfiguration? -> - Timber.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}") - }) - recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? -> - Timber.i("recognizeNotice observe notice = $notice") - }) - - recognizeViewModel.recognizeUserId.observe( - activity, - Observer { compareResult: CompareResult -> - Timber.i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}") - recognitionTime = System.currentTimeMillis() - recognitionWeight = lastWeight - lastFaceTrackId = compareResult.trackId - val faceEntity = compareResult.faceEntity - val userId = faceEntity.userName - if (userId == null) return@Observer - viewModel.getUserNutritionData( - userId = userId, - foodId = currentFood!!.id!! - ) - }) - - recognizeViewModel.drawRectInfoText.observe(activity, Observer { info -> - Timber.i("drawRectInfoText observe info = $info") - }) - } - - private fun initArcView() { - //在布局结束后才做初始化操作 - binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this) - recognizeViewModel.getCompareResultList().getValue() - } - - /** - * 调整View的宽高,使预览显示正常且采集框固定为 - * - * @param rgbPreview RGB预览View - * @param previewView 显示预览数据的view - * @param faceRectView 画框的view - * @param previewSize 预览大小 - * @param displayOrientation 相机旋转角度 - * @param scale 缩放比例 - * @return 调整后的LayoutParams - */ - private fun adjustPreviewViewSize( - rgbPreview: View, - previewView: View, - faceRectView: FaceRectView, - previewSize: Camera.Size, - displayOrientation: Int, - scale: Float - ): ViewGroup.LayoutParams { - val layoutParams = previewView.layoutParams - val measuredWidth = previewView.measuredWidth - val measuredHeight = previewView.measuredHeight - var ratio = (previewSize.height.toFloat()) / previewSize.width.toFloat() - if (ratio > 1) { - ratio = 1 / ratio - } - if (displayOrientation % 180 == 0) { - layoutParams.width = measuredWidth - layoutParams.height = (measuredWidth * ratio).toInt() - } else { - layoutParams.height = measuredHeight - layoutParams.width = (measuredHeight * ratio).toInt() - } - if (scale < 1f) { - val rgbParam = rgbPreview.getLayoutParams() - layoutParams.width = (rgbParam.width * scale).toInt() - layoutParams.height = (rgbParam.height * scale).toInt() - } else { - layoutParams.width = (layoutParams.width * scale).toInt() - layoutParams.height = (layoutParams.height * scale).toInt() - } - - val metrics = DisplayMetrics() - activity.windowManager.defaultDisplay.getMetrics(metrics) - - if (layoutParams.width >= metrics.widthPixels) { - val viewRatio = layoutParams.width / (metrics.widthPixels.toFloat()) - layoutParams.width = (layoutParams.width / viewRatio).toInt() - layoutParams.height = (layoutParams.height / viewRatio).toInt() - } - if (layoutParams.height >= metrics.heightPixels) { - val viewRatio = layoutParams.height / (metrics.heightPixels.toFloat()) - layoutParams.width = (layoutParams.width / viewRatio).toInt() - layoutParams.height = (layoutParams.height / viewRatio).toInt() - } - - previewView.setLayoutParams(layoutParams) - faceRectView.setLayoutParams(layoutParams) - return layoutParams - } - - private fun initRgbCamera() { - val cameraListener: CameraListener = object : CameraListener { - override fun onCameraOpened( - camera: Camera, - cameraId: Int, - displayOrientation: Int, - isMirror: Boolean - ) { - Timber.d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") - activity.runOnUiThread({ - val previewSizeRgb = camera.getParameters().getPreviewSize() - val layoutParams = adjustPreviewViewSize( - binding.dualCameraTexturePreviewRgb, - binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, - previewSizeRgb, displayOrientation, 0.6F - ) - Timber.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") - Timber.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") - Timber.d( - "initRgbCamera isMirror = ${isMirror}, isDrawRgbRectHorizontalMirror = ${ - ConfigUtil.isDrawRgbRectHorizontalMirror( - context - ) - }, isDrawRgbRectVerticalMirror = ${ - ConfigUtil.isDrawRgbRectVerticalMirror( - context - ) - }" - ) - // 调整识别窗口位置 - rgbFaceRectTransformer = FaceRectTransformer( - previewSizeRgb.width, - previewSizeRgb.height, - layoutParams.width, - layoutParams.height, - 90, - cameraId, - isMirror, - true, - true - ) - - recognizeViewModel.onRgbCameraOpened(camera) - recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer) - }) - } - - @RequiresApi(api = Build.VERSION_CODES.Q) - override fun onPreview(nv21: ByteArray?, camera: Camera?) { - if (!isRecognition) { - return - } - binding.dualCameraFaceRectView.clearFaceInfo() - val facePreviewInfoList: MutableList? = - recognizeViewModel.onPreviewFrame(nv21, true) - if (facePreviewInfoList != null && rgbFaceRectTransformer != null) { - drawPreviewInfo(facePreviewInfoList) - } - recognizeViewModel.clearLeftFace(facePreviewInfoList) - } - - override fun onCameraClosed() { - Timber.i("initRgbCamera onCameraClosed: ") - } - - override fun onCameraError(e: java.lang.Exception) { - Timber.i("initRgbCamera onCameraError: %s", e.message) - e.printStackTrace() - } - - override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) { - Timber.i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}") - if (rgbFaceRectTransformer != null) { - rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation - } - Timber.i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation") - } - } - - val previewConfig: PreviewConfig = recognizeViewModel.previewConfig - rgbCameraHelper = DualCameraHelper.Builder() - .previewViewSize( - Point( - binding.dualCameraTexturePreviewRgb.measuredWidth, - binding.dualCameraTexturePreviewRgb.measuredHeight - ) - ) - .rotation(activity.windowManager.defaultDisplay.rotation) - .additionalRotation(previewConfig.rgbAdditionalDisplayOrientation) // 角度 - .previewSize(recognizeViewModel.loadPreviewSize()) - .specificCameraId(previewConfig.rgbCameraId) - .isMirror(true) - .previewOn(binding.dualCameraTexturePreviewRgb) - .cameraListener(cameraListener) - .build() - rgbCameraHelper!!.init() - rgbCameraHelper!!.start() - } - - /** - * 初始化红外相机,若活体检测类型是可见光活体检测或不启用活体,则不需要启用 - */ - private fun initIrCamera() { - Timber.d("initIrCamera: livenessType = $livenessType") - if (livenessType === LivenessType.RGB) { - return - } - val irCameraListener: CameraListener = object : CameraListener { - override fun onCameraOpened( - camera: Camera, - cameraId: Int, - displayOrientation: Int, - isMirror: Boolean - ) { - Timber.d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") - val previewSizeIr = camera.getParameters().getPreviewSize() - val layoutParams = adjustPreviewViewSize( - binding.dualCameraTexturePreviewRgb, - binding.dualCameraTexturePreviewIr, binding.dualCameraFaceRectViewIr, - previewSizeIr, displayOrientation, 0.25f - ) - - irFaceRectTransformer = FaceRectTransformer( - previewSizeIr.width, previewSizeIr.height, - layoutParams.width, layoutParams.height, displayOrientation, cameraId, isMirror, - ConfigUtil.isDrawIrRectHorizontalMirror(context), - ConfigUtil.isDrawIrRectVerticalMirror(context) - ) - - recognizeViewModel.onIrCameraOpened(camera) - recognizeViewModel.setIrFaceRectTransformer(irFaceRectTransformer) - } - - - override fun onPreview(nv21: ByteArray?, camera: Camera?) { - recognizeViewModel.refreshIrPreviewData(nv21) - } - - override fun onCameraClosed() { - Timber.i("initIrCamera onCameraClosed: ") - } - - override fun onCameraError(e: java.lang.Exception) { - Timber.i("initIrCamera onCameraError: ${e.message}") - e.printStackTrace() - } - - override fun onCameraConfigurationChanged( - cameraID: Int, - displayOrientation: Int - ) { - if (irFaceRectTransformer != null) { - irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation - } - Timber.i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation") - } - } - - val previewConfig = recognizeViewModel.previewConfig - irCameraHelper = DualCameraHelper.Builder() - .previewViewSize( - Point( - binding.dualCameraTexturePreviewIr.measuredWidth, - binding.dualCameraTexturePreviewIr.measuredHeight - ) - ) - .rotation(activity.windowManager.defaultDisplay.rotation) - .specificCameraId(previewConfig.irCameraId) - .previewOn(binding.dualCameraTexturePreviewIr) - .cameraListener(irCameraListener) - .isMirror(true) - .previewSize(recognizeViewModel.loadPreviewSize()) //相机预览大小设置,RGB与IR需使用相同大小 - .additionalRotation(previewConfig.irAdditionalDisplayOrientation) //额外旋转角度 - .build() - irCameraHelper!!.init() - try { - irCameraHelper!!.start() - } catch (e: RuntimeException) { - ToastUtils.showToast(e.message + context.getString(R.string.camera_error_notice)) - } - } - - /** - * 绘制RGB、IR画面的实时人脸信息 - * - * @param facePreviewInfoList RGB画面的实时人脸信息 - */ - private fun drawPreviewInfo(facePreviewInfoList: MutableList) { -// Timber.d("drawPreviewInfo facePreviewInfoList = ${facePreviewInfoList.size}, rgbFaceRectTransformer = ${rgbFaceRectTransformer != null}") - if (rgbFaceRectTransformer != null) { - val rgbDrawInfoList: MutableList? = recognizeViewModel.getDrawInfo( - facePreviewInfoList, - LivenessType.RGB, - openRectInfoDraw - ) - // 识别成功 - binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList) - } - - if (facePreviewInfoList.isEmpty() || (lastFaceTrackId != facePreviewInfoList[0]!!.trackId)) { - if (lastFaceTrackId != -1) { - Timber.i("$lastFaceTrackId 用户离开") - lastFaceTrackId = -1 - postUserData() - if (mealPickupMode == 0) { - step1() - } else { - step2(currentFood!!) - } - } - } - } - - fun postUserData() { - Timber.d("postUserData") - if (userNutritionData == null || currentFood == null) { - Timber.d("postUserData userNutritionData = ${userNutritionData == null}, currentFood = ${currentFood == null}") - return - } - var eatWeight = 0.0 - if (mealPickupMode == 0) {//即放即取 - eatWeight = recognitionWeight - 0 - } else { - eatWeight = recognitionWeight - lastWeight - } - val userNutritionParam = UserNutritionParam( - userId = userNutritionData?.userId!!, - foodId = currentFood?.id!!, - faceTime = recognitionTime, - faceEndTime = System.currentTimeMillis(), - eatWeight = eatWeight,//lastWeight - foodWeight = lastWeight - ) - viewModel.postUserNutritionData(listOf(userNutritionParam)) - } - - fun openRectInfoDraw(view: View?) { - openRectInfoDraw = !openRectInfoDraw - recognizeViewModel.setDrawRectInfoTextValue(openRectInfoDraw) - } - - - override fun onGlobalLayout() { - Timber.d("onGlobalLayout") - binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this) - openCamera() - } - - -// override fun onResume() { -// super.onResume() -// resumeCamera() -// viewModel.resetUserInfo() +//package com.sw.dualscreen.presentation +// +//import android.Manifest +//import android.app.Presentation +//import android.content.Context +//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.util.DisplayMetrics +//import android.view.Display +//import android.view.View +//import android.view.ViewGroup +//import android.view.ViewOutlineProvider +//import android.view.ViewTreeObserver +//import androidx.annotation.RequiresApi +//import androidx.core.content.ContextCompat +//import androidx.lifecycle.Observer +//import androidx.lifecycle.lifecycleScope +//import com.arcsoft.face.ErrorInfo +//import com.sw.dualscreen.R +//import com.sw.dualscreen.activity.MainActivity +//import com.sw.dualscreen.databinding.ItemUserNutritionBinding +//import com.sw.dualscreen.databinding.PresentationSecondaryScreenBinding +//import com.sw.dualscreen.ext.dp +//import com.sw.dualscreen.ext.format2String +//import com.sw.dualscreen.ext.maskName +//import com.sw.dualscreen.model.request.UserNutritionParam +//import com.sw.dualscreen.model.response.DinnerTypeInfo +//import com.sw.dualscreen.model.response.FoodInfo +//import com.sw.dualscreen.model.response.UserNutritionData +//import com.sw.dualscreen.utils.Debouncer +//import com.sw.dualscreen.utils.GlideUtils +//import com.sw.dualscreen.viewmodel.UserViewModel +//import com.sw.plate.utils.LightManager +//import com.sw.plate.utils.ToastUtils +//import com.sw.plate.utils.arcface.ConfigUtil +//import com.sw.plate.utils.arcface.ErrorCodeUtil +//import com.sw.plate.utils.arcface.FaceRectTransformer +//import com.sw.plate.utils.arcface.FaceRectView +//import com.sw.plate.utils.arcface.FaceRectView.DrawInfo +//import com.sw.plate.utils.arcface.PreviewConfig +//import com.sw.plate.utils.arcface.camera.CameraListener +//import com.sw.plate.utils.arcface.camera.DualCameraHelper +//import com.sw.plate.utils.arcface.face.constants.LivenessType +//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 kotlinx.coroutines.flow.drop +//import kotlinx.coroutines.launch +//import timber.log.Timber +// +///** +// * 用户屏幕 +// */ +//class SecondaryScreenPresentation( +// val activity: MainActivity, +// context: Context, +// display: Display, +// val viewModel: UserViewModel, +// private val onDismissListener: () -> Unit = {}, +// val recognizeViewModel: RecognizeViewModel +//) : Presentation(context, display), ViewTreeObserver.OnGlobalLayoutListener { +// private lateinit var binding: PresentationSecondaryScreenBinding +// +// // 当前食物信息 +// private var currentFood: FoodInfo? = null +// private var userNutritionData: UserNutritionData? = null +// private var dinnerTypeInfo: DinnerTypeInfo? = null +// private lateinit var itemUserNutritionBinding: ItemUserNutritionBinding +// private lateinit var stepChangeCallback: (Int) -> Unit +// +// +// private var detectWeight = 0.0 //识别菜品时的重量 +// private var lastWeight = 0.0 // 上一次的计算热量结果 +// private val debouncer = Debouncer(500) +// private var recognitionTime: Long = 0L // 人脸识别时的时间 +// private var recognitionWeight: Double = 0.0 // 人脸识别时的重量 +// private var lastFaceTrackId: Int = -1 // 上一次的人脸信息 +// var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐 +// +// // 当前步骤 +// var currentStep: Int = 0 +// +// private var isGoStep1 = false;//防止持续调用 +// +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// +// binding = PresentationSecondaryScreenBinding.inflate(layoutInflater) +// setContentView(binding.root) +// window?.setBackgroundDrawableResource(android.R.color.transparent) +// initView() +// setupArcCamera() +// registerDataChange() // } // -// protected override fun onPause() { -// pauseCamera() -// super.onPause() +// private fun registerDataChange() { +// activity.lifecycleScope.launch { +// viewModel.loadFaceResult.collect { needUpdate -> +// if (needUpdate) { +// recognizeViewModel.refreshFaceList() +// } +// } +// } +// activity.lifecycleScope.launch { +// viewModel.nutritionData.collect { +// Timber.d("registerDataChange nutritionData = $it") +// userNutritionData = it +// if (it == null) return@collect +// step3() +// itemUserNutritionBinding.tvUserName.text = it.userName.maskName() +// itemUserNutritionBinding.tvRecommendHeat.text = +// "推荐热量:${it.recommendMin}-${it.recommendMax}" +// +// updateWeight(lastWeight / 1000) +// } +// } +// activity.lifecycleScope.launch { +// viewModel.dinnerTypeInfo.drop(1).collect { +// Timber.d("registerDataChange dinnerTypeInfo = $it") +// dinnerTypeInfo = it +// } +// } // } - - override fun onStop() { - if (rgbCameraHelper != null) { - rgbCameraHelper!!.release() - rgbCameraHelper = null - } - if (irCameraHelper != null) { - irCameraHelper!!.release() - irCameraHelper = null - } - recognizeViewModel.destroy() - super.onStop() - } - - fun resumeCamera() { - Timber.d("resumeCamera isRecognition = $isRecognition") - isRecognition = true - if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) { - rgbCameraHelper!!.start() - } - } - - fun pauseCamera() { - Timber.d("pauseCamera isRecognition = $isRecognition") - isRecognition = false - - recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) - } -} \ No newline at end of file +// +// private fun initView() { +// binding.ivImg.outlineProvider = object : ViewOutlineProvider() { +// override fun getOutline(view: View, outline: Outline) { +// outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) +// } +// } +// binding.ivImg.clipToOutline = true +// itemUserNutritionBinding = binding.includeUserNutrition +// } +// +// override fun onDisplayRemoved() { +// super.onDisplayRemoved() +// onDismissListener() +// } +// +// fun updateImage(bitmap: Bitmap) { +// activity.runOnUiThread { +// binding.ivImg.setImageBitmap(bitmap) +// } +// } +// +// /** +// * 启用虹软人脸失败 +// */ +// private fun setupArcCamera() { +// initArcViewModel() +// initArcView() +// openRectInfoDraw = true +// } +// +// /** +// * 用户1 显示相机预览 +// */ +// fun step1() { +// Timber.d("step1") +// currentStep = 1 +// LightManager.closeGreenLight() +// LightManager.closeRedLight() +// //回复上一次的设置 +//// lastWeight = 0.0 +// dinnerTypeInfo = null +// currentFood = null +// userNutritionData = null +// recognitionWeight = 0.0 +// +// stepChangeCallback(currentStep) +// binding.tvFoodName.text = "菜品识别中" +// binding.ivFaceBg.visibility = View.GONE +// binding.flPreview.visibility = View.VISIBLE +// binding.ivImg.visibility = View.VISIBLE +// binding.flFace.visibility = View.INVISIBLE +// binding.tvFaceTip.visibility = View.GONE +// pauseCamera() +// binding.tvBottomTip.visibility = View.VISIBLE +// itemUserNutritionBinding.clNutritionData.visibility = View.GONE +// +// activity.clearFoodList() +// } +// +// /** +// * 显示人脸识别 +// */ +// fun step2(foodInfo: FoodInfo) { +// isGoStep1 = true +// Timber.d("step2") +// currentStep = 2 +// LightManager.closeRedLight() +//// LightManager.openGreenLight() +// dinnerTypeInfo = null +// userNutritionData = null +// recognitionWeight = 0.0 +// +// stepChangeCallback(currentStep) +// currentFood = foodInfo +// viewModel.getDinnerType() +// resumeCamera() +// binding.tvFoodName.text = foodInfo.foodName +// binding.ivImg.visibility = View.GONE +// +// binding.flPreview.visibility = View.GONE +// +//// binding.flFace.visibility = View.VISIBLE +// binding.flFace.post { +// binding.flFace.visibility = View.VISIBLE +// } +// binding.ivFaceBg.visibility = View.VISIBLE +// binding.tvFaceTip.visibility = View.VISIBLE +// binding.tvBottomTip.visibility = View.VISIBLE +// itemUserNutritionBinding.clNutritionData.visibility = View.GONE +// } +// +// fun updateFood(foodInfo: FoodInfo?) { +// Timber.d("updateFood") +// currentFood = foodInfo +// if (foodInfo != null) { +// if (currentStep == 1) { +// step2(foodInfo) +// } else { +// updateFoodInfo(foodInfo) +// } +// } +// } +// +// /** +// * 显示识别出的菜品信息 +// */ +// fun step3() { +// Timber.d("step3") +// LightManager.closeRedLight() +// LightManager.openGreenLight() +// currentStep = 3 +// stepChangeCallback(currentStep) +// if (currentFood == null) { +// ToastUtils.showToast("选中物品为空3") +// return +// } +// updateFoodInfo(currentFood!!) +// binding.flPreview.visibility = View.VISIBLE +// binding.ivImg.visibility = View.VISIBLE +// binding.flFace.visibility = View.INVISIBLE +// binding.ivFaceBg.visibility = View.GONE +// binding.tvFaceTip.visibility = View.GONE +// +// binding.tvBottomTip.visibility = View.GONE +// itemUserNutritionBinding.clNutritionData.visibility = View.VISIBLE +// } +// +// private fun updateFoodInfo(foodInfo: FoodInfo) { +// binding.tvFoodName.text = foodInfo.foodName +// if (foodInfo.photoUri != null) { +// GlideUtils.loadRoundCornerImage( +// context, +// url = foodInfo.photoUri, +// imageView = binding.ivImg, +// radius = 12 +// ) +// } else { +// GlideUtils.loadRoundCornerImage( +// context, +// url = foodInfo.imgUrl, +// imageView = binding.ivImg, +// radius = 12 +// ) +// } +// } +// +// fun updateWeight(weight: Double) { +// lastWeight = weight * 1000 // 将千克转成克 +// Timber.d("updateWeight lastWeight = $weight") +// if (currentStep == 2 && +// lastWeight <= 5 && +// isGoStep1 +// ) {//人脸识别过程中,秤上物品拿走 +// isGoStep1 = false +// activity.runOnUiThread { +// Timber.e("切回step1") +// step1() +// } +// } +// +// +// if (currentFood == null) { +// Timber.e("updateWeight currentFood is null") +// return +// } +// +// +// if (userNutritionData == null) { +// Timber.e("updateWeight userNutritionData is null") +// return +// } +// if (dinnerTypeInfo == null) { +// Timber.e("updateWeight dinnerType is null") +// return +// } +// calculateNutrition(recognitionWeight - lastWeight) +// } +// +// fun updateDetectWeight(weight: Double) { +// detectWeight = weight * 1000 // 将千克转成克 +// } +// +// /** +// * 余量取餐 +// */ +// fun updateMealPickupMode(mode: Int) { +// Timber.d("updateMealPickupMode mode = $mode") +// mealPickupMode = mode +// step1() +// } +// +// private fun calculateNutrition(weight1: Double) { +// var weight = weight1 +// if (weight < 0) weight = 0.0 +// debouncer.debounce { +// Timber.d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight") +// val dinnerType = dinnerTypeInfo!!.dinnerType!!.dinnerType!! +// Timber.d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}") +// val calcResultInfo = UserNutritionUtils.calculateNutrition( +// currentFood!!, +// userNutritionData!!, +// weight, +// dinnerType = dinnerType +// ) +// Timber.d("calculateNutrition calcResultInfo = $calcResultInfo") +// val columnMax = UserNutritionUtils.getMaxInt(calcResultInfo) +// +// activity.runOnUiThread { +// val totalKcal = calcResultInfo.totalKcal +// val grain = calcResultInfo.grain +// val fruits = calcResultInfo.fruits +// val meat = calcResultInfo.meat +// // 设置热量 +// itemUserNutritionBinding.customKcalColumn.setImageDrawable( +// true, +// totalKcal.max < totalKcal.current +// ) +// var maxKcal = totalKcal.max +// Timber.d("maxKcal = $maxKcal") +// // 避免0作为被除数 +// if (maxKcal <= 0.0) { +// maxKcal = 1.0 +// } +// Timber.d("maxKcal 1 = $maxKcal") +// itemUserNutritionBinding.totalKcalTv.text = totalKcal.current.format2String() +// var totalKcalHeight = (totalKcal.current / maxKcal).toFloat() +// if (totalKcalHeight == 0F) { +// itemUserNutritionBinding.divKcalView.visibility = View.VISIBLE +// } else { +// itemUserNutritionBinding.divKcalView.visibility = View.GONE +// totalKcalHeight += 0.1F +// } +// itemUserNutritionBinding.customKcalColumn.setCustomHeightPercent( +// totalKcalHeight, +// true +// ) +// +// // 设置主食 +// itemUserNutritionBinding.customFoodColumn.setImageDrawable( +// false, +// grain.max < grain.current +// ) +// itemUserNutritionBinding.totalFoodTv.text = grain.current.format2String() +// var grainHeight = (grain.current / columnMax).toFloat() +// if (grainHeight == 0F) { +// itemUserNutritionBinding.divTotalFoodView.visibility = View.VISIBLE +// } else { +// itemUserNutritionBinding.divTotalFoodView.visibility = View.GONE +// grainHeight += 0.1F +// } +// itemUserNutritionBinding.customFoodColumn.setCustomHeightPercent( +// grainHeight, +// true +// ) +// +// // 设置果蔬 +// itemUserNutritionBinding.customVegetableColumn.setImageDrawable( +// false, +// fruits.max < fruits.current +// ) +// itemUserNutritionBinding.totalVegetableTv.text = fruits.current.format2String() +// var fruitsHeight = (fruits.current / columnMax).toFloat() +// +// if (fruitsHeight == 0F) { +// itemUserNutritionBinding.divVegetableView.visibility = View.VISIBLE +// } else { +// itemUserNutritionBinding.divVegetableView.visibility = View.GONE +// fruitsHeight += 0.1F +// } +// itemUserNutritionBinding.customVegetableColumn.setCustomHeightPercent( +// fruitsHeight, +// true +// ) +// +// // 设置肉蛋 +// itemUserNutritionBinding.customMeatColumn.setImageDrawable( +// false, +// meat.max < meat.current +// ) +// itemUserNutritionBinding.totalMeatTv.text = meat.current.format2String() +// var meatHeight = (meat.current / columnMax).toFloat() +// if (meatHeight == 0F) { +// itemUserNutritionBinding.divMeatView.visibility = View.VISIBLE +// } else { +// itemUserNutritionBinding.divMeatView.visibility = View.GONE +// meatHeight += 0.1F +// } +// itemUserNutritionBinding.customMeatColumn.setCustomHeightPercent( +// meatHeight, +// true +// ) +// } +// } +// } +// +// private fun openCamera() { +// Timber.d("openCamera") +// if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != +// PackageManager.PERMISSION_GRANTED +// ) { +// ToastUtils.showToast("无摄像头权限") +// return +// } +// try { +// val cameraCount = Camera.getNumberOfCameras() +// if (cameraCount < 3) { +// ToastUtils.showToast("摄像头数量异常") +// return +// } +// recognizeViewModel.init( +// PreviewConfig( +// 2, 1, 90, 90 +// ) +// ) +// initRgbCamera() +// if (DualCameraHelper.hasDualCamera() && livenessType === LivenessType.IR) { +// initIrCamera() +// } +// } catch (e: Exception) { +// Timber.e(e, "打开摄像头失败") +// } +// } +// +// fun setStepChangeCallback(callback: (Int) -> Unit) { +// stepChangeCallback = callback +// } +// +// // 虹软人脸配置 ⬇ +// private var isRecognition = false +// private var rgbCameraHelper: DualCameraHelper? = null +// private var rgbFaceRectTransformer: FaceRectTransformer? = null +// private val livenessType = LivenessType.IR +// private var openRectInfoDraw = false +// +// private var irCameraHelper: DualCameraHelper? = null +// private var irFaceRectTransformer: FaceRectTransformer? = null +// +// private fun initArcViewModel() { +// +// recognizeViewModel.setLiveType(livenessType) +// +// recognizeViewModel.ftInitCode.observe(activity, Observer { ftInitCode: Int? -> +// if (ftInitCode != ErrorInfo.MOK) { +// val error: String? = context.getString( +// R.string.specific_engine_init_failed, "ftEngine", +// ftInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(ftInitCode!!) +// ) +// Timber.e("ftInitCode observe = $error") +// ToastUtils.showToast(error) +// } +// }) +// recognizeViewModel.frInitCode.observe(activity, Observer { frInitCode: Int? -> +// if (frInitCode != ErrorInfo.MOK) { +// val error: String? = context.getString( +// R.string.specific_engine_init_failed, "frEngine", +// frInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(frInitCode!!) +// ) +// Timber.e("frInitCode observe = $error") +// ToastUtils.showToast(error) +// } +// }) +// recognizeViewModel.flInitCode.observe(activity, Observer { flInitCode: Int? -> +// if (flInitCode != ErrorInfo.MOK) { +// val error: String? = context.getString( +// R.string.specific_engine_init_failed, "flEngine", +// flInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(flInitCode!!) +// ) +// Timber.e("flInitCode observe = $error") +// ToastUtils.showToast(error) +// } +// }) +// +// recognizeViewModel.recognizeConfiguration +// .observe(activity, Observer { recognizeConfiguration: RecognizeConfiguration? -> +// Timber.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}") +// }) +// recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? -> +// Timber.i("recognizeNotice observe notice = $notice") +// }) +// +// recognizeViewModel.recognizeUserId.observe( +// activity, +// Observer { compareResult: CompareResult -> +// Timber.i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}") +// recognitionTime = System.currentTimeMillis() +// recognitionWeight = lastWeight +// lastFaceTrackId = compareResult.trackId +// val faceEntity = compareResult.faceEntity +// val userId = faceEntity.userName +// if (userId == null) return@Observer +// viewModel.getUserNutritionData( +// userId = userId, +// foodId = currentFood!!.foodId!! +// ) +// }) +// +// recognizeViewModel.drawRectInfoText.observe(activity, Observer { info -> +// Timber.i("drawRectInfoText observe info = $info") +// }) +// } +// +// private fun initArcView() { +// //在布局结束后才做初始化操作 +// binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this) +// recognizeViewModel.getCompareResultList().getValue() +// } +// +// /** +// * 调整View的宽高,使预览显示正常且采集框固定为 +// * +// * @param rgbPreview RGB预览View +// * @param previewView 显示预览数据的view +// * @param faceRectView 画框的view +// * @param previewSize 预览大小 +// * @param displayOrientation 相机旋转角度 +// * @param scale 缩放比例 +// * @return 调整后的LayoutParams +// */ +// private fun adjustPreviewViewSize( +// rgbPreview: View, +// previewView: View, +// faceRectView: FaceRectView, +// previewSize: Camera.Size, +// displayOrientation: Int, +// scale: Float +// ): ViewGroup.LayoutParams { +// val layoutParams = previewView.layoutParams +// val measuredWidth = previewView.measuredWidth +// val measuredHeight = previewView.measuredHeight +// var ratio = (previewSize.height.toFloat()) / previewSize.width.toFloat() +// if (ratio > 1) { +// ratio = 1 / ratio +// } +// if (displayOrientation % 180 == 0) { +// layoutParams.width = measuredWidth +// layoutParams.height = (measuredWidth * ratio).toInt() +// } else { +// layoutParams.height = measuredHeight +// layoutParams.width = (measuredHeight * ratio).toInt() +// } +// if (scale < 1f) { +// val rgbParam = rgbPreview.getLayoutParams() +// layoutParams.width = (rgbParam.width * scale).toInt() +// layoutParams.height = (rgbParam.height * scale).toInt() +// } else { +// layoutParams.width = (layoutParams.width * scale).toInt() +// layoutParams.height = (layoutParams.height * scale).toInt() +// } +// +// val metrics = DisplayMetrics() +// activity.windowManager.defaultDisplay.getMetrics(metrics) +// +// if (layoutParams.width >= metrics.widthPixels) { +// val viewRatio = layoutParams.width / (metrics.widthPixels.toFloat()) +// layoutParams.width = (layoutParams.width / viewRatio).toInt() +// layoutParams.height = (layoutParams.height / viewRatio).toInt() +// } +// if (layoutParams.height >= metrics.heightPixels) { +// val viewRatio = layoutParams.height / (metrics.heightPixels.toFloat()) +// layoutParams.width = (layoutParams.width / viewRatio).toInt() +// layoutParams.height = (layoutParams.height / viewRatio).toInt() +// } +// +// previewView.setLayoutParams(layoutParams) +// faceRectView.setLayoutParams(layoutParams) +// return layoutParams +// } +// +// private fun initRgbCamera() { +// val cameraListener: CameraListener = object : CameraListener { +// override fun onCameraOpened( +// camera: Camera, +// cameraId: Int, +// displayOrientation: Int, +// isMirror: Boolean +// ) { +// Timber.d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") +// activity.runOnUiThread({ +// val previewSizeRgb = camera.getParameters().getPreviewSize() +// val layoutParams = adjustPreviewViewSize( +// binding.dualCameraTexturePreviewRgb, +// binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, +// previewSizeRgb, displayOrientation, 0.6F +// ) +// Timber.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") +// Timber.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") +// Timber.d( +// "initRgbCamera isMirror = ${isMirror}, isDrawRgbRectHorizontalMirror = ${ +// ConfigUtil.isDrawRgbRectHorizontalMirror( +// context +// ) +// }, isDrawRgbRectVerticalMirror = ${ +// ConfigUtil.isDrawRgbRectVerticalMirror( +// context +// ) +// }" +// ) +// // 调整识别窗口位置 +// rgbFaceRectTransformer = FaceRectTransformer( +// previewSizeRgb.width, +// previewSizeRgb.height, +// layoutParams.width, +// layoutParams.height, +// 90, +// cameraId, +// isMirror, +// true, +// true +// ) +// +// recognizeViewModel.onRgbCameraOpened(camera) +// recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer) +// }) +// } +// +// @RequiresApi(api = Build.VERSION_CODES.Q) +// override fun onPreview(nv21: ByteArray?, camera: Camera?) { +// if (!isRecognition) { +// return +// } +// binding.dualCameraFaceRectView.clearFaceInfo() +// val facePreviewInfoList: MutableList? = +// recognizeViewModel.onPreviewFrame(nv21, true) +// if (facePreviewInfoList != null && rgbFaceRectTransformer != null) { +// drawPreviewInfo(facePreviewInfoList) +// } +// recognizeViewModel.clearLeftFace(facePreviewInfoList) +// } +// +// override fun onCameraClosed() { +// Timber.i("initRgbCamera onCameraClosed: ") +// } +// +// override fun onCameraError(e: java.lang.Exception) { +// Timber.i("initRgbCamera onCameraError: %s", e.message) +// e.printStackTrace() +// } +// +// override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) { +// Timber.i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}") +// if (rgbFaceRectTransformer != null) { +// rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation +// } +// Timber.i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation") +// } +// } +// +// val previewConfig: PreviewConfig = recognizeViewModel.previewConfig +// rgbCameraHelper = DualCameraHelper.Builder() +// .previewViewSize( +// Point( +// binding.dualCameraTexturePreviewRgb.measuredWidth, +// binding.dualCameraTexturePreviewRgb.measuredHeight +// ) +// ) +// .rotation(activity.windowManager.defaultDisplay.rotation) +// .additionalRotation(previewConfig.rgbAdditionalDisplayOrientation) // 角度 +// .previewSize(recognizeViewModel.loadPreviewSize()) +// .specificCameraId(previewConfig.rgbCameraId) +// .isMirror(true) +// .previewOn(binding.dualCameraTexturePreviewRgb) +// .cameraListener(cameraListener) +// .build() +// rgbCameraHelper!!.init() +// rgbCameraHelper!!.start() +// } +// +// /** +// * 初始化红外相机,若活体检测类型是可见光活体检测或不启用活体,则不需要启用 +// */ +// private fun initIrCamera() { +// Timber.d("initIrCamera: livenessType = $livenessType") +// if (livenessType === LivenessType.RGB) { +// return +// } +// val irCameraListener: CameraListener = object : CameraListener { +// override fun onCameraOpened( +// camera: Camera, +// cameraId: Int, +// displayOrientation: Int, +// isMirror: Boolean +// ) { +// Timber.d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") +// val previewSizeIr = camera.getParameters().getPreviewSize() +// val layoutParams = adjustPreviewViewSize( +// binding.dualCameraTexturePreviewRgb, +// binding.dualCameraTexturePreviewIr, binding.dualCameraFaceRectViewIr, +// previewSizeIr, displayOrientation, 0.25f +// ) +// +// irFaceRectTransformer = FaceRectTransformer( +// previewSizeIr.width, previewSizeIr.height, +// layoutParams.width, layoutParams.height, displayOrientation, cameraId, isMirror, +// ConfigUtil.isDrawIrRectHorizontalMirror(context), +// ConfigUtil.isDrawIrRectVerticalMirror(context) +// ) +// +// recognizeViewModel.onIrCameraOpened(camera) +// recognizeViewModel.setIrFaceRectTransformer(irFaceRectTransformer) +// } +// +// +// override fun onPreview(nv21: ByteArray?, camera: Camera?) { +// recognizeViewModel.refreshIrPreviewData(nv21) +// } +// +// override fun onCameraClosed() { +// Timber.i("initIrCamera onCameraClosed: ") +// } +// +// override fun onCameraError(e: java.lang.Exception) { +// Timber.i("initIrCamera onCameraError: ${e.message}") +// e.printStackTrace() +// } +// +// override fun onCameraConfigurationChanged( +// cameraID: Int, +// displayOrientation: Int +// ) { +// if (irFaceRectTransformer != null) { +// irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation +// } +// Timber.i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation") +// } +// } +// +// val previewConfig = recognizeViewModel.previewConfig +// irCameraHelper = DualCameraHelper.Builder() +// .previewViewSize( +// Point( +// binding.dualCameraTexturePreviewIr.measuredWidth, +// binding.dualCameraTexturePreviewIr.measuredHeight +// ) +// ) +// .rotation(activity.windowManager.defaultDisplay.rotation) +// .specificCameraId(previewConfig.irCameraId) +// .previewOn(binding.dualCameraTexturePreviewIr) +// .cameraListener(irCameraListener) +// .isMirror(true) +// .previewSize(recognizeViewModel.loadPreviewSize()) //相机预览大小设置,RGB与IR需使用相同大小 +// .additionalRotation(previewConfig.irAdditionalDisplayOrientation) //额外旋转角度 +// .build() +// irCameraHelper!!.init() +// try { +// irCameraHelper!!.start() +// } catch (e: RuntimeException) { +// ToastUtils.showToast(e.message + context.getString(R.string.camera_error_notice)) +// } +// } +// +// /** +// * 绘制RGB、IR画面的实时人脸信息 +// * +// * @param facePreviewInfoList RGB画面的实时人脸信息 +// */ +// private fun drawPreviewInfo(facePreviewInfoList: MutableList) { +//// Timber.d("drawPreviewInfo facePreviewInfoList = ${facePreviewInfoList.size}, rgbFaceRectTransformer = ${rgbFaceRectTransformer != null}") +// if (rgbFaceRectTransformer != null) { +// val rgbDrawInfoList: MutableList? = recognizeViewModel.getDrawInfo( +// facePreviewInfoList, +// LivenessType.RGB, +// openRectInfoDraw +// ) +// // 识别成功 +// binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList) +// } +// +// if (facePreviewInfoList.isEmpty() || (lastFaceTrackId != facePreviewInfoList[0]!!.trackId)) { +// if (lastFaceTrackId != -1) { +// Timber.i("$lastFaceTrackId 用户离开") +// lastFaceTrackId = -1 +// postUserData() +// if (mealPickupMode == 0) { +// step1() +// } else { +// step2(currentFood!!) +// } +// } +// } +// } +// +// fun postUserData() { +// Timber.d("postUserData") +// if (userNutritionData == null || currentFood == null) { +// Timber.d("postUserData userNutritionData = ${userNutritionData == null}, currentFood = ${currentFood == null}") +// return +// } +// var eatWeight = 0.0 +// if (mealPickupMode == 0) {//即放即取 +// eatWeight = recognitionWeight - 0 +// } else { +// eatWeight = recognitionWeight - lastWeight +// } +// val userNutritionParam = UserNutritionParam( +// userId = userNutritionData?.userId!!, +// foodId = currentFood?.foodId!!, +// faceTime = recognitionTime, +// faceEndTime = System.currentTimeMillis(), +// eatWeight = eatWeight,//lastWeight +// foodWeight = lastWeight +// ) +// viewModel.postUserNutritionData(listOf(userNutritionParam)) +// } +// +// fun openRectInfoDraw(view: View?) { +// openRectInfoDraw = !openRectInfoDraw +// recognizeViewModel.setDrawRectInfoTextValue(openRectInfoDraw) +// } +// +// +// override fun onGlobalLayout() { +// Timber.d("onGlobalLayout") +// binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this) +// openCamera() +// } +// +// +//// override fun onResume() { +//// super.onResume() +//// resumeCamera() +//// viewModel.resetUserInfo() +//// } +//// +//// protected override fun onPause() { +//// pauseCamera() +//// super.onPause() +//// } +// +// override fun onStop() { +// if (rgbCameraHelper != null) { +// rgbCameraHelper!!.release() +// rgbCameraHelper = null +// } +// if (irCameraHelper != null) { +// irCameraHelper!!.release() +// irCameraHelper = null +// } +// recognizeViewModel.destroy() +// super.onStop() +// } +// +// fun resumeCamera() { +// Timber.d("resumeCamera isRecognition = $isRecognition") +// isRecognition = true +// if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) { +// rgbCameraHelper!!.start() +// } +// } +// +// fun pauseCamera() { +// Timber.d("pauseCamera isRecognition = $isRecognition") +// isRecognition = false +// +// recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) +// } +//} \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/repository/BaseRepository.kt b/app/src/main/java/com/sw/dualscreen/repository/BaseRepository.kt index 8fa2bff..f34eeaa 100644 --- a/app/src/main/java/com/sw/dualscreen/repository/BaseRepository.kt +++ b/app/src/main/java/com/sw/dualscreen/repository/BaseRepository.kt @@ -18,31 +18,31 @@ abstract class BaseRepository { when (e) { is HttpException -> { - ApiResponse(code = e.code(), message = e.message()) + ApiResponse(code = "${e.code()}", msg = e.message()) } is SocketTimeoutException -> { - ApiResponse(code = -2, message = "请求超时: ${e.message}") + ApiResponse(code = "-2", msg = "请求超时: ${e.message}") } is ConnectException -> { - ApiResponse(code = -3, message = "连接失败: ${e.message}") + ApiResponse(code = "-3", msg = "连接失败: ${e.message}") } is SSLHandshakeException -> { - ApiResponse(code = -4, message = "SSL握手失败: ${e.message}") + ApiResponse(code = "-4", msg = "SSL握手失败: ${e.message}") } is JsonParseException -> { - ApiResponse(code = -5, message = "JSON解析错误: ${e.message}") + ApiResponse(code = "-5", msg = "JSON解析错误: ${e.message}") } is IOException -> { - ApiResponse(code = -6, message = "网络IO错误: ${e.message}") + ApiResponse(code = "-6", msg = "网络IO错误: ${e.message}") } else -> { - ApiResponse(code = -1, message = "未知错误: ${e.message ?: "无错误信息"}") + ApiResponse(code = "-1", msg = "未知错误: ${e.message ?: "无错误信息"}") } } } diff --git a/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt b/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt index 4698238..a61bc47 100644 --- a/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt +++ b/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt @@ -5,15 +5,20 @@ import android.net.Uri import com.sw.dualscreen.GlobalData import com.sw.dualscreen.model.request.UserNutritionParam import com.sw.dualscreen.model.response.ApiResponse -import com.sw.dualscreen.model.response.DinnerTypeInfo -import com.sw.dualscreen.model.response.EquipmentInfo +import com.sw.dualscreen.model.response.DinnerType import com.sw.dualscreen.model.response.FoodInfo -import com.sw.dualscreen.model.response.UserFaceInfo +import com.sw.dualscreen.model.response.FoodSearchReq +import com.sw.dualscreen.model.response.UserFaceModel import com.sw.dualscreen.model.response.UserNutritionData import com.sw.dualscreen.network.api.ApiService +import com.sw.dualscreen.objbox.CollectedFoodInfo import com.sw.dualscreen.utils.ImageUtil +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File /** * 远程数据处理 @@ -24,43 +29,65 @@ class RemoteRepository constructor( /** * 生成token */ - suspend fun getDeviceToken(qrcodeId: String): ApiResponse { - return safeApiCall { - apiService.getDeviceToken( - qrcodeId - ) - } - } +// suspend fun getDeviceToken(qrcodeId: String): ApiResponse { +// return safeApiCall { +// apiService.getDeviceToken( +// qrcodeId +// ) +// } +// } /** * 获取设备信息 */ - suspend fun getDeviceInfo(equipmentCode: String, token: String): ApiResponse { - return safeApiCall { - apiService.getDeviceInfo( - equipmentCode, - token = token - ) - } - } +// suspend fun getDeviceInfo(equipmentCode: String, token: String): ApiResponse { +// return safeApiCall { +// apiService.getDeviceInfo( +// equipmentCode, +// token = token +// ) +// } +// } /** * 获取业务服务器token */ - suspend fun getEquipmentToken(qrcodeId: String): ApiResponse { - return safeApiCall { - apiService.getEquipmentToken(qrcodeId = qrcodeId) - } - } +// suspend fun getEquipmentToken(qrcodeId: String): ApiResponse { +// return safeApiCall { +// apiService.getEquipmentToken(qrcodeId = qrcodeId) +// } +// } /** * 获取人脸数据 */ suspend fun getUserFaceCache( - pageIndex: Int - ): ApiResponse { + pageNum: Int, + pageSize: Int = 100, + ): ApiResponse> { return safeApiCall { - apiService.getUserFaceCache(pageIndex = pageIndex) + apiService.getUserFaceCache( + param = mapOf( + "pageNum" to pageNum, + "pageSize" to pageSize + ) + ) + } + } + /** + * 获取人脸数据 + */ + suspend fun getCollectedFoodList( + pageNum: Int, + pageSize: Int = 50, + ): ApiResponse> { + return safeApiCall { + apiService.getCollectedFoodList( + param = mapOf( + "pageNum" to pageNum, + "pageSize" to pageSize + ) + ) } } @@ -75,7 +102,7 @@ class RemoteRepository constructor( foodName: String, ): ApiResponse> { return safeApiCall { - apiService.getRestInfoFoodsByType(restId = restId, type = type, foodName = foodName) + apiService.getRestInfoFoodsByType(foodName = foodName) } } @@ -93,10 +120,10 @@ class RemoteRepository constructor( } suspend fun getDinnerType( - restId: String = GlobalData.restId, - ): ApiResponse { +// restId: String = GlobalData.restId, + ): ApiResponse { return safeApiCall { - apiService.getDinnerType(restId = restId) + apiService.getDinnerType() } } @@ -118,29 +145,31 @@ class RemoteRepository constructor( restId: String = GlobalData.restId, foodName: String, ): ApiResponse> { - return safeApiCall { apiService.getFoodInfo(restId = restId, foodName = foodName) } + return safeApiCall { +// val map = mutableMapOf>() +// map["nameList"] = foodName.split(",") + apiService.getFoodInfo(req = FoodSearchReq(nameList = foodName.split(","))) + } } + /** - * 获取菜品信息 - * @param restId 从device服务获取的canteenId字段 - * @param foodName 菜品名称,多个使用逗号拼接 + * 上传采集菜品信息 */ - suspend fun postImageData( - context: Context, - restId: String = GlobalData.restId, - foodId: String, - foodName: String, - foodVector: String, - uri: Uri, - ): ApiResponse { - - val params = HashMap() - params["placeId"] = restId.toRequestBody() - params["foodId"] = foodId.toRequestBody() - params["foodName"] = foodName.toRequestBody() - params["foodVector"] = foodVector.toRequestBody() - val imagePart = ImageUtil.uriToMultipart(context, uri, "foodPic") - - return safeApiCall { apiService.postImageData(params = params, image = imagePart) } + suspend fun uploadCollectFoodPics(fileList: List, params: HashMap): ApiResponse { + // 准备文件参数 + val fileParts = mutableListOf() + fileList.forEachIndexed { index, file -> + val requestFile = file + .asRequestBody("multipart/form-data".toMediaTypeOrNull()) + val filePart = MultipartBody.Part.createFormData( + "foodPics", + file.name, + requestFile + ) + fileParts.add(filePart) + } + return safeApiCall { + apiService.uploadCollectFoodPics(params = params, foodPics = fileParts) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt b/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt index aa59848..79e3325 100644 --- a/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt +++ b/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt @@ -15,6 +15,15 @@ object ImageUtil { fun uriToBitmap(context: Context, uri: Uri): Bitmap? { return try { + val options = BitmapFactory.Options() + //options.inSampleSize = 2; // 这会将图片的尺寸缩小到原来的1/2 + options.inJustDecodeBounds = false +// options.inPreferredConfig = Bitmap.Config.ARGB_8888 + options.inPreferredConfig = Bitmap.Config.RGB_565 + context.contentResolver.openInputStream(uri)?.use { stream -> + BitmapFactory.decodeStream(stream, null, options) +// BitmapFactory.decodeStream(stream) + } context.contentResolver.openInputStream(uri)?.use { stream -> BitmapFactory.decodeStream(stream) } diff --git a/app/src/main/java/com/sw/dualscreen/viewmodel/BaseViewModel.kt b/app/src/main/java/com/sw/dualscreen/viewmodel/BaseViewModel.kt index cdc763f..1f45d68 100644 --- a/app/src/main/java/com/sw/dualscreen/viewmodel/BaseViewModel.kt +++ b/app/src/main/java/com/sw/dualscreen/viewmodel/BaseViewModel.kt @@ -52,25 +52,25 @@ abstract class BaseViewModel() : ViewModel() { } protected open fun parseResponse(response: ApiResponse<*>): Boolean { - if (response.isSuccess() - || response.code == 200 - || response.code == 0 - ) { + val code = response.code + if (code == "00000" || code == "200" || code == "0") { return true } - Timber.d("msg = ${response.message}, code = ${response.code}") - ToastUtils.showToast("${response.message}(${response.code})") + val message = response.message?:response.msg + Timber.d("msg = ${message}, code = $code") + ToastUtils.showToast("${message}(${code})") return false } - fun parseEquipmentInfo(equipmentInfo: EquipmentInfo) { - GlobalData.appBaseUrl = equipmentInfo.appPackageUrl!! - //GlobalData.appBaseUrl="http://192.168.1.210/gateway/local" - GlobalData.sdkKey = equipmentInfo.arcsoftSdkKey!! - GlobalData.appId = equipmentInfo.arcsoftAppId!! -// GlobalData.activeKey = equipmentInfo.arcsoftActiveKey!! - GlobalData.restId = equipmentInfo.canteenId!! - } +// fun parseEquipmentInfo(equipmentInfo: EquipmentInfo) { +// //GlobalData.appBaseUrl = equipmentInfo.appPackageUrl!! +// GlobalData.appBaseUrl = "http://192.168.1.201:14801" +// //GlobalData.appBaseUrl="http://192.168.1.210/gateway/local" +// GlobalData.sdkKey = equipmentInfo.arcsoftSdkKey!! +// GlobalData.appId = equipmentInfo.arcsoftAppId!! +//// GlobalData.activeKey = equipmentInfo.arcsoftActiveKey!! +// GlobalData.restId = equipmentInfo.canteenId!! +// } fun handleError(exception: Exception) { Timber.d("handleError ${exception.message}") diff --git a/app/src/main/java/com/sw/dualscreen/viewmodel/DeviceViewModel.kt b/app/src/main/java/com/sw/dualscreen/viewmodel/DeviceViewModel.kt index 587e08d..ebb74f4 100644 --- a/app/src/main/java/com/sw/dualscreen/viewmodel/DeviceViewModel.kt +++ b/app/src/main/java/com/sw/dualscreen/viewmodel/DeviceViewModel.kt @@ -19,49 +19,49 @@ class DeviceViewModel : BaseViewModel() { /** * 获取token */ - fun getDeviceToken(deviceId: String = GlobalData.deviceId) { - launchWithLoading { - val response = repository.getDeviceToken(deviceId) - if (parseResponse(response)) { - val response1 = repository.getDeviceInfo(deviceId, response.result!!) - - if (parseResponse(response1)) { - val equipmentInfo = response1.result - if (equipmentInfo == null) return@launchWithLoading - try { - parseEquipmentInfo(equipmentInfo) - SPUtil.getInstance() - .put(GlobalKey.KEY_EQUIPMENT_INFO, GsonUtils.toJson(equipmentInfo)) - _deviceInfoResult.value = true - } catch (e: Exception) { - Timber.e(e) - } - } - } - } - } +// fun getDeviceToken(deviceId: String = GlobalData.deviceId) { +// launchWithLoading { +// val response = repository.getDeviceToken(deviceId) +// if (parseResponse(response)) { +// val response1 = repository.getDeviceInfo(deviceId, response.result!!) +// +// if (parseResponse(response1)) { +// val equipmentInfo = response1.result +// if (equipmentInfo == null) return@launchWithLoading +// try { +// parseEquipmentInfo(equipmentInfo) +// SPUtil.getInstance() +// .put(GlobalKey.KEY_EQUIPMENT_INFO, GsonUtils.toJson(equipmentInfo)) +// _deviceInfoResult.value = true +// } catch (e: Exception) { +// Timber.e(e) +// } +// } +// } +// } +// } /** * 检查缓存数据 */ - fun checkEquipmentInfo(): Boolean { - val equipmentInfoStr = SPUtil.getInstance().get(GlobalKey.KEY_EQUIPMENT_INFO, "") - if (equipmentInfoStr == null) { - Timber.e("获取缓存设备信息失败") - return false - } - val equipmentInfo = - GsonUtils.fromJson(equipmentInfoStr, EquipmentInfo::class.java) - if (equipmentInfo == null) { - Timber.e("解析缓存设备信息失败") - return false - } - try { - parseEquipmentInfo(equipmentInfo) - return true - } catch (e: Exception) { - Timber.e(e) - return false - } - } +// fun checkEquipmentInfo(): Boolean { +// val equipmentInfoStr = SPUtil.getInstance().get(GlobalKey.KEY_EQUIPMENT_INFO, "") +// if (equipmentInfoStr == null) { +// Timber.e("获取缓存设备信息失败") +// return false +// } +// val equipmentInfo = +// GsonUtils.fromJson(equipmentInfoStr, EquipmentInfo::class.java) +// if (equipmentInfo == null) { +// Timber.e("解析缓存设备信息失败") +// return false +// } +// try { +// parseEquipmentInfo(equipmentInfo) +// return true +// } catch (e: Exception) { +// Timber.e(e) +// return false +// } +// } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt b/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt index d8dd2c5..1feb718 100644 --- a/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt +++ b/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt @@ -1,16 +1,15 @@ package com.sw.dualscreen.viewmodel -import android.content.Context -import android.net.Uri import androidx.lifecycle.viewModelScope import com.arcsoft.face.ErrorInfo import com.sw.dualscreen.GlobalData import com.sw.dualscreen.GlobalKey import com.sw.dualscreen.model.request.UserNutritionParam -import com.sw.dualscreen.model.response.DinnerTypeInfo +import com.sw.dualscreen.model.response.DinnerType import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.UserFaceModel import com.sw.dualscreen.model.response.UserNutritionData +import com.sw.dualscreen.objbox.CollectedFoodInfo import com.sw.dualscreen.utils.SPUtil import com.sw.plate.App import com.sw.plate.utils.Base64 @@ -22,10 +21,15 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import okhttp3.RequestBody import timber.log.Timber -import kotlin.math.atan +import java.io.File class UserViewModel : BaseViewModel() { + companion object { + private const val TAG = "UserViewModel" + const val PAGE_SIZE = 100 + } private val faceApi: FaceApi = FaceApi() @@ -44,8 +48,8 @@ class UserViewModel : BaseViewModel() { /** * 饭点类型 早餐/午餐/晚餐 */ - private val _dinnerTypeInfo = MutableStateFlow(null) - val dinnerTypeInfo: StateFlow = _dinnerTypeInfo + private val _dinnerTypeInfo = MutableStateFlow(null) + val dinnerTypeInfo: StateFlow = _dinnerTypeInfo /** * 人脸加载完成 @@ -59,45 +63,66 @@ class UserViewModel : BaseViewModel() { * 获取token */ fun getEquipmentToken(qrcodeId: String = GlobalData.deviceId) { - Timber.d("getEquipmentToken") - launchWithLoading { - val response = repository.getEquipmentToken(qrcodeId) - if (parseResponse(response)) { - // 缓存token - SPUtil.getInstance().put(GlobalKey.KEY_TOKEN, response.result) - // 首次运行获取人脸数据 - if (SPUtil.getInstance().get(GlobalKey.KEY_FIRST_RUN, false) != true) { - getUserFaceCache(index = 0) - } - } - } +// Timber.tag(TAG).d("getEquipmentToken") +// launchWithLoading { +// val response = repository.getEquipmentToken(qrcodeId) +// if (parseResponse(response)) { +// // 缓存token +// SPUtil.getInstance().put(GlobalKey.KEY_TOKEN, response.result) +// // 首次运行获取人脸数据 +// if (SPUtil.getInstance().get(GlobalKey.KEY_FIRST_RUN, false) != true) { +// getUserFaceCache(pageNo = 1) +// } +// } +// } } /** * 获取人脸数据 */ - fun getUserFaceCache(index: Int = 0) { - Timber.d("getUserFaceCache index = $index") + fun getUserFaceCache(pageNo: Int = 1, pageSize: Int = PAGE_SIZE) { + var currentPageNo = pageNo + Timber.tag(TAG).d("getUserFaceCache index = $currentPageNo") launch { _loadFaceResult.value = false - val response = repository.getUserFaceCache(index) + val response = repository.getUserFaceCache(currentPageNo) if (parseResponse(response)) { // 获取成功一次后缓存状态 SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true) withContext(Dispatchers.Default) { - val list: List = response.result?.data ?: emptyList() + val list: List = response.result ?: emptyList() val item = list.firstOrNull { it.userId == "1951105919342936066" } - Timber.d("getUserFaceCache userId = ${item?.userId}") + Timber.tag(TAG).d("getUserFaceCache userId = ${item?.userId}") val faceEntity = list.map { - FaceEntity(it.userId, null, Base64.decode(it.faceFeatureString)) + FaceEntity(it.userId, null, Base64.decode(it.faceFeatureStr)) + } + faceApi.updateFaceData(currentPageNo, faceEntity) + if (list.size >= pageSize) { + currentPageNo++ + getUserFaceCache(currentPageNo) + } else { + _loadFaceResult.value = true } - faceApi.updateFaceData(index, faceEntity) } - val nextPageIndex = response.result?.nextPageIndex ?: -1 - if (nextPageIndex > 0) { - getUserFaceCache(nextPageIndex) - } else { - _loadFaceResult.value = true + +// val nextPageIndex = response.result?.nextPageIndex ?: -1 +// if (nextPageIndex > 0) { +// getUserFaceCache(nextPageIndex) +// } else { +// _loadFaceResult.value = true +// } + } + } + } + + fun getCollectedFoodList(pageNo: Int = 1, pageSize: Int = 100, block:(List)-> Unit) { + Timber.tag(TAG).d("getCollectedFoodList index = $pageNo") + launch { + val response = repository.getCollectedFoodList(pageNo) + if (parseResponse(response)) { + withContext(Dispatchers.Default) { + val list: List = response.result ?: emptyList() + block(list) } } } @@ -107,7 +132,7 @@ class UserViewModel : BaseViewModel() { * 激活人脸识别引擎 */ fun activeEngine() { - Timber.d("activeEngine") + Timber.tag(TAG).d("activeEngine") faceApi.activeEngine( App.getContext(), @@ -116,7 +141,7 @@ class UserViewModel : BaseViewModel() { GlobalData.activeKey, object : FaceApi.ActiveCallback { override fun onSuccess(activeCode: Int) { - Timber.d("activeEngine activeCode = $activeCode") + Timber.tag(TAG).d("activeEngine activeCode = $activeCode") viewModelScope.launch(Dispatchers.Main) { when (activeCode) { ErrorInfo.MOK -> { @@ -142,18 +167,18 @@ class UserViewModel : BaseViewModel() { }) } - fun getIdentifiedFoodList() { - Timber.d("identifiedFoodList") - launchWithLoading { - val response = repository.getRestInfoFoodsByType(foodName = "") - if (parseResponse(response)) { - _identifiedFoodInfoList.value = response.result ?: emptyList() - } - } - } +// fun getIdentifiedFoodList() { +// Timber.tag(TAG).d("identifiedFoodList") +// launchWithLoading { +// val response = repository.getRestInfoFoodsByType(foodName = "") +// if (parseResponse(response)) { +// _identifiedFoodInfoList.value = response.result ?: emptyList() +// } +// } +// } fun cleanIdentifiedFoodInfoList() { - Timber.d("cleanIdentifiedFoodInfoList") + Timber.tag(TAG).d("cleanIdentifiedFoodInfoList") _identifiedFoodInfoList.value = emptyList() } @@ -161,19 +186,19 @@ class UserViewModel : BaseViewModel() { * 搜索食物 */ fun searchByFoodName(foodName: String, action: (List) -> Unit = {}) { - Timber.d("searchByFoodName foodName = $foodName") + Timber.tag(TAG).d("searchByFoodName foodName = $foodName") launchWithLoading { val response = repository.getRestInfoFoodsByType(foodName = foodName) if (parseResponse(response)) { val list = response.result ?: emptyList() action(list) - _searchFoodInfoList.value = list + _identifiedFoodInfoList.value = response.result ?: emptyList() } } } fun cleanSearchFoodInfoList() { - Timber.d("cleanSearchFoodInfoList") + Timber.tag(TAG).d("cleanSearchFoodInfoList") _searchFoodInfoList.value = emptyList() } @@ -181,7 +206,7 @@ class UserViewModel : BaseViewModel() { * 获取用户就餐数据 */ fun getUserNutritionData(userId: String, foodId: String) { - Timber.d("getUserNutritionData userId = ${userId}, foodId = $foodId") + Timber.tag(TAG).d("getUserNutritionData userId = ${userId}, foodId = $foodId") _nutritionData.value = null launch { val response = repository.getUserNutritionData(userId = userId, foodId = foodId) @@ -192,7 +217,7 @@ class UserViewModel : BaseViewModel() { } fun getDinnerType() { - Timber.d("getDinnerType") + Timber.tag(TAG).d("getDinnerType") _dinnerTypeInfo.value = null launch { val response = repository.getDinnerType() @@ -206,7 +231,7 @@ class UserViewModel : BaseViewModel() { * 提交就餐数据 */ fun postUserNutritionData(param: List) { - Timber.d("postUserNutritionData param = $param") + Timber.tag(TAG).d("postUserNutritionData param = $param") launch { val response = repository.postUserNutritionData(param) if (parseResponse(response)) { @@ -215,13 +240,13 @@ class UserViewModel : BaseViewModel() { } } - fun getFoodInfo(foodName: String, action:(List)-> Unit = {}) { - Timber.d("getFoodInfo") + fun getFoodInfo(foodName: String, action: (List) -> Unit = {}) { + Timber.tag(TAG).d("getFoodInfo") launchWithLoading { val response = repository.getFoodInfo(foodName = foodName) if (parseResponse(response)) { val list = response.result ?: emptyList() - _identifiedFoodInfoList2.value = list + _identifiedFoodInfoList.value = list action(list) } else { action(emptyList()) @@ -229,22 +254,22 @@ class UserViewModel : BaseViewModel() { } } - fun postImageData( - context: Context, - foodId: String, - foodName: String, - foodVector: String, - uri: Uri - ) { - Timber.d("postImageData") + + + fun uploadCollectFoodPics(files: List, params: HashMap, callback: (Boolean) -> Unit) { + Timber.tag(TAG).d("uploadCollectFoodPics") launchWithLoading { - val response = repository.postImageData( - context, foodId = foodId, foodName = foodName, foodVector = foodVector, - uri = uri - ) - if (parseResponse(response)) { - Timber.tag("mzf").d("code=${response.code}") + val fileList = files.filterNotNull() + if (fileList.isEmpty()) { + callback(false) + return@launchWithLoading } + val resp = repository.uploadCollectFoodPics(fileList, params) + if (!parseResponse(resp)) { + callback(false) + return@launchWithLoading + } + callback(resp.code == "00000") } } } \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_search.xml b/app/src/main/res/drawable/bg_search.xml index b09b31d..f4c0e7c 100644 --- a/app/src/main/res/drawable/bg_search.xml +++ b/app/src/main/res/drawable/bg_search.xml @@ -3,5 +3,5 @@ android:shape="rectangle"> + android:radius="50dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_init.xml b/app/src/main/res/layout/activity_init.xml index bae0ef8..fe50d0c 100644 --- a/app/src/main/res/layout/activity_init.xml +++ b/app/src/main/res/layout/activity_init.xml @@ -63,7 +63,8 @@ android:text="设备初始化" android:textColor="@color/white" android:textSize="30sp" - android:textStyle="bold" /> + android:textStyle="bold" + android:visibility="invisible"/> + tools:src="@mipmap/ic_launcher" + android:visibility="invisible"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index fa9f16c..17b9cb2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -104,37 +104,41 @@ android:layout_marginTop="42dp" android:layout_weight="1" /> - + + + + + + + + - + + + + + + - - + + + + + + + + + + + + + + + + + android:textSize="36sp" /> + android:textSize="36sp" /> @@ -64,7 +64,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="500dp" - android:layout_marginTop="42dp" + android:layout_marginTop="48dp" android:layout_marginBottom="20dp" android:layout_marginHorizontal="14dp" app:spanCount="2" diff --git a/app/src/main/res/layout/list_item_collected_food.xml b/app/src/main/res/layout/list_item_collected_food.xml index 139245e..47c2a8c 100644 --- a/app/src/main/res/layout/list_item_collected_food.xml +++ b/app/src/main/res/layout/list_item_collected_food.xml @@ -44,6 +44,7 @@ android:layout_marginEnd="75dp" android:paddingHorizontal="10dp" android:src="@drawable/ic_close2" - tools:ignore="ContentDescription" /> + tools:ignore="ContentDescription" + android:visibility="gone"/> \ No newline at end of file diff --git a/app/src/main/res/layout/presentation_main_screen.xml b/app/src/main/res/layout/presentation_main_screen.xml index 6da0c35..2fb8668 100644 --- a/app/src/main/res/layout/presentation_main_screen.xml +++ b/app/src/main/res/layout/presentation_main_screen.xml @@ -82,11 +82,11 @@ android:layout_height="456dp" tools:background="@mipmap/ic_launcher"/> - + + + + + + android:visibility="gone"> list) { Log.d(TAG, "updateFaceData: index = " + index + ", listSize = " + list.size()); FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao(); - if (index == 0) { + if (index == 1) { faceDao.deleteAll(); faceDao.resetId(); }