From 750d92e2f9d42bdc536a1ae6b928c388ef8857ca Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Tue, 11 Nov 2025 11:52:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A5=E5=BA=93=E5=8A=9F=E8=83=BD=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=9B=B8=E6=9C=BA=E9=A2=84=E8=A7=88=E5=8F=8A=E6=8B=8D?= =?UTF-8?q?=E7=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/FoodCollectionActivity.kt | 76 ---------- .../sw/inbound/dialog/GoodsRecognizeDialog.kt | 10 +- .../sw/inbound/dialog/GoodsSearchDialog.kt | 6 +- .../com/sw/inbound/dialog/GoodsStoreDialog.kt | 125 +++++++++++++++- .../java/com/sw/inbound/objbox/FoodModule.kt | 2 +- .../java/com/sw/inbound/utils/CrashHandler.kt | 4 +- .../main/res/layout/dialog_goods_store.xml | 13 +- .../res/layout/layout_empty_recognize.xml | 2 +- .../main/res/layout/layout_image_preview.xml | 13 ++ app/src/main/res/layout/layout_take_photo.xml | 137 ++++++++++++++++++ 10 files changed, 295 insertions(+), 93 deletions(-) create mode 100644 app/src/main/res/layout/layout_image_preview.xml create mode 100644 app/src/main/res/layout/layout_take_photo.xml diff --git a/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt b/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt index 0ab6ed6..287ff67 100644 --- a/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt +++ b/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt @@ -67,11 +67,6 @@ class FoodCollectionActivity : ComponentActivity() { } private val collectionAdapter: FoodCollectionAdapter by lazy { FoodCollectionAdapter(collectList).apply { -// setOnItemClickListener { _, _, position -> -// if (collectList[position].isShowCamera) { -// takePhoto() -// } -// } addOnItemChildClickListener(R.id.ivDelete) { _, _, position -> collectList[position].let { it.bitmap = null @@ -79,13 +74,6 @@ class FoodCollectionActivity : ComponentActivity() { it.isShowCamera = true } collectionAdapter.notifyItemChanged(position) -// if (position == collectList.size - 1) { -// -// return@addOnItemChildClickListener -// } -// collectList.removeAt(position) -// adapter.notifyItemRemoved(position) -// adapter.notifyItemRangeChanged(position, collectList.size) } } } @@ -156,25 +144,6 @@ class FoodCollectionActivity : ComponentActivity() { binding.btnCollectedGoods.setOnClickListener { CollectSearchDialog(this@FoodCollectionActivity).show() } -// binding.btnAddDefault.clickWithDebounce { -// Thread{ -// FoodModule.initDefFoodData(this) { -// runOnUiThread { -// toast("添加完成") -// } -// } -// }.start() -// } -// binding.btnRemoveDefault.clickWithDebounce { -// initBox() -// val list = box?.all?.filter { it.foodIdx == FoodModule.DEFAULT_FOOD_INDEX } -// if (list.isNullOrEmpty()) { -// toast("不存在默认数据") -// return@clickWithDebounce -// } -// box?.removeByIds(list.map { it.id }) -// toast("移除完成") -// } binding.btnClearData.setOnClickListener { clearData() } binding.rvSearch.let { it.layoutManager = GridLayoutManager(this, 2, LinearLayoutManager.VERTICAL, false) @@ -191,49 +160,10 @@ class FoodCollectionActivity : ComponentActivity() { searchGoods() } } -// binding.radioGroup.setOnCheckedChangeListener { group, checkedId -> -// if (checkedId == R.id.rbCollected) { -// binding.llSearchInput.gone() -// binding.refreshLayout.let { -// it.setEnableRefresh(false) -// it.setEnableLoadMore(false) -// } -// getCollectedGoods() -// return@setOnCheckedChangeListener -// } -// if (checkedId == R.id.rbSearch) { -// binding.llSearchInput.visible() -// pageNo = 1 -// clickIndex = -1 -// searchGoodsList.clear() -// searchAdapter.notifyDataSetChanged() -// binding.refreshLayout.let { -// it.setEnableRefresh(true) -// it.setEnableLoadMore(false) -// } -// loadEmptyView() -// return@setOnCheckedChangeListener -// } -// } -// binding.radioGroup.check(R.id.rbCollected) loadEmptyView() } - @SuppressLint("NotifyDataSetChanged") - private fun getCollectedGoods() { - searchGoodsList.clear() - initBox() - box?.all?.distinctBy { it.name }?.forEach { - searchGoodsList.add((SearchGoodsInfo.Record(goodsName = it.name))) - } - binding.rvSearch.layoutManager = GridLayoutManager(this, 2, LinearLayoutManager.VERTICAL, false) - searchAdapter.notifyDataSetChanged() - if (searchGoodsList.isEmpty()) { - loadEmptyView() - } - } - private var pageNo = 1 private var clickIndex = -1 @@ -313,12 +243,6 @@ class FoodCollectionActivity : ComponentActivity() { it.isShowCamera = false } collectionAdapter.notifyItemChanged(index) -// if (collectList.size < 6) { -// collectList.add(collectList.size - 1, FoodCollectionBean(bitmap = cropBitmap)) -// } else { -// collectList[collectList.size - 1] = FoodCollectionBean(bitmap = cropBitmap) -// } -// adapter.notifyDataSetChanged() } } diff --git a/app/src/main/java/com/sw/inbound/dialog/GoodsRecognizeDialog.kt b/app/src/main/java/com/sw/inbound/dialog/GoodsRecognizeDialog.kt index c861e28..9420728 100644 --- a/app/src/main/java/com/sw/inbound/dialog/GoodsRecognizeDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/GoodsRecognizeDialog.kt @@ -15,8 +15,8 @@ import java.io.File @SuppressLint("NotifyDataSetChanged") class GoodsRecognizeDialog( context: Context, - var goodsFile: File?=null, - var goodsName: String?=null, + var goodsFile: File? = null, + var goodsName: String? = null, var list: MutableList, //var closeCallback:()->Unit, var findGoods: () -> Unit @@ -55,7 +55,11 @@ class GoodsRecognizeDialog( } private fun showGoodsStoreDialog(position: Int) { - GoodsStoreDialog(context, list[position]) { + GoodsStoreDialog( + context = context, + funcType = 0, + goods = list[position] + ) { activity?.addGoods(it) activity?.startTime = System.currentTimeMillis() dismiss() diff --git a/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt b/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt index f9d2fce..750ea9a 100644 --- a/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt @@ -63,7 +63,11 @@ class GoodsSearchDialog( context.toast("请选择物品") return@setOnClickListener } - GoodsStoreDialog(context, list[clickIndex]) { + GoodsStoreDialog( + context = context, + funcType = 1, + goods = list[clickIndex] + ) { activity?.addGoods(it) activity?.startTime = System.currentTimeMillis() activity?.goodsRecognizeDialog?.dismiss() diff --git a/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt b/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt index 9578783..634e5ec 100644 --- a/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt @@ -2,6 +2,7 @@ package com.sw.inbound.dialog import android.content.Context import android.graphics.Typeface +import android.net.Uri import android.text.InputType import android.text.SpannableStringBuilder import android.text.style.ForegroundColorSpan @@ -9,6 +10,7 @@ import android.text.style.StyleSpan import android.view.LayoutInflater import android.view.View import android.widget.EditText +import androidx.camera.view.PreviewView import androidx.core.graphics.toColorInt import androidx.core.widget.addTextChangedListener import coil.load @@ -16,15 +18,29 @@ import com.shuwei.intelligent.shelves.utils.ext.appendText import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString import com.sw.inbound.activity.GoodsListActivity import com.sw.inbound.databinding.DialogGoodsStoreBinding +import com.sw.inbound.databinding.LayoutImagePreviewBinding +import com.sw.inbound.databinding.LayoutTakePhotoBinding import com.sw.inbound.ext.toFormattedString import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.GoodsInfo import com.sw.inbound.model.response.SearchGoodsInfo +import com.sw.inbound.objbox.Food +import com.sw.inbound.objbox.FoodModule +import com.sw.inbound.objbox.ObjectBox import com.sw.inbound.sdk.SensorScaleUtils +import com.sw.inbound.utils.BitmapCropper +import com.sw.inbound.utils.BitmapSaver +import com.sw.inbound.utils.CameraUtils +import com.sw.inbound.utils.ImageUtil import com.sw.inbound.utils.ext.dp +import com.sw.inbound.utils.ext.gone import com.sw.inbound.utils.ext.roundedDecimalPlace import com.sw.inbound.utils.ext.toast +import com.sw.inbound.utils.ext.visible import com.sw.inbound.utils.removeTrailingZeros +import io.objectbox.Box +import io.objectbox.kotlin.boxFor +import timber.log.Timber import kotlin.Int import kotlin.math.abs import kotlin.math.min @@ -32,6 +48,7 @@ import kotlin.math.min class GoodsStoreDialog( context: Context, var goods: SearchGoodsInfo.Record, + var funcType: Int, var cancelBlock: () -> Unit = {}, var confirmBlock: (GoodsInfo) -> Unit = {}, ) : BaseDialog(context) { @@ -65,7 +82,9 @@ class GoodsStoreDialog( setText(goods.goodsName) isEnabled = false } - binding.ivGoodsImage.load(goods.relativeUrl) + //binding.ivGoodsImage.load(goods.relativeUrl) + addChildToContainer() + //flContainer binding.btnCancel.setOnClickListener { cancelBlock() dismiss() @@ -101,9 +120,12 @@ class GoodsStoreDialog( } val first = goods.unitVoList!!.first { it.businessUnitId == dictType.id } val stringBuilder = StringBuilder() - .append("1").append(dictType.value).append("=").append(first.purchaseValue!!.toInt().toString()).append(goods.kcUnitName) + .append("1").append(dictType.value).append("=") + .append(first.purchaseValue!!.toInt().toString()) + .append(goods.kcUnitName) .append(",") - .append("1").append(goods.kcUnitName).append("=").append(first.consumeValue).append("克") + .append("1").append(goods.kcUnitName).append("=") + .append(first.consumeValue).append("克") binding.tvUnitCalculate.text = stringBuilder.toString() //val count = getUnitCount(dictType.id!!) //if (count.isBlank() || "0" == count) { @@ -249,6 +271,10 @@ class GoodsStoreDialog( } private fun confirmInputData() { + if (funcType == 1 && imageUri == null) { + context.toast("请采集图片") + return + } val unit = binding.tvProcurementUnit.text.trim().toString() if (unit.isBlank()) { context.toast("请选择入库单位") @@ -288,6 +314,9 @@ class GoodsStoreDialog( context.toast("入库金额不能为0") return } + if (funcType == 1) { + collectGoodsVector() + } val id = binding.tvProcurementUnit.tag.toString() val unitVo = goods.unitVoList!!.first { it.businessUnitId == id } confirmBlock( @@ -320,8 +349,96 @@ class GoodsStoreDialog( private fun getUnitCount(id: String): String { val first = goods.unitVoList!!.first { it.businessUnitId == id } - val count = first.getPurchaseUnitValue( this.realWeight) + val count = first.getPurchaseUnitValue(this.realWeight) return count } + private val cameraUtils: CameraUtils by lazy { + CameraUtils(activity!!) + } + + override fun show() { + super.show() + takePhotoBinding?.let { + cameraUtils.setPreviewController(previewView) + cameraUtils.bind() + it.llCameraFlag.run { + postDelayed({ + gone() + }, 1000) + } + } + } + + private var imageUri: Uri? = null + private val takePhotoCallback: (Uri) -> Unit = { uri -> + takePhotoBinding?.let { + imageUri = uri + it.flCameraPreview.gone() + it.cvImageBg.visible() + it.ivGoodsImage.load(uri) + } + } + + private var previewView: PreviewView? = null + private var takePhotoBinding: LayoutTakePhotoBinding? = null + private var imagePreviewBinding: LayoutImagePreviewBinding? = null + private fun addChildToContainer() { + val inflater = LayoutInflater.from(context) + if (funcType == 1) { + //预览及拍照 + takePhotoBinding = LayoutTakePhotoBinding.inflate(inflater, binding.flContainer, true) + activity?.unBindCamera() + setOnDismissListener { + cameraUtils.unbind() + } + cameraUtils.initCamera() + takePhotoBinding?.let { + previewView = it.previewView + it.flCameraPreview.visible() + it.cvImageBg.gone() + it.btnStartPreview.setOnClickListener { _ -> + it.cvImageBg.gone() + it.flCameraPreview.visible() + } + it.btnTakePhoto.setOnClickListener { _ -> + cameraUtils.takePhoto(takePhotoCallback) + } + } + return + } + //只显示原始图片 + imagePreviewBinding = LayoutImagePreviewBinding.inflate(inflater, binding.flContainer) + imagePreviewBinding?.imageView?.load(goods.relativeUrl) + } + + private var box: Box? = null + private fun collectGoodsVector() { + try { + ImageUtil.uriToBitmap(context, imageUri!!)?.let { bitmap -> + val cropBitmap = BitmapCropper.cropCenter( + original = bitmap, + targetWidth = 1000, targetHeight = 1300, + offsetX = 30, offsetY = 100 + ) + val file = BitmapSaver.saveToAppFilesDir( + cropBitmap, context, "IMG_CROP_${System.currentTimeMillis()}.jpg" + ) + Timber.d("${this.javaClass.simpleName}-collectGoodsVector-裁剪bitmap保存文件路径:${file?.absolutePath}") + if (box == null) { + box = ObjectBox.boxStore.boxFor(Food::class) + } + Thread { + try { + val imageVector = FoodModule.bitmap2FloatArray(bitmap) + box?.put(Food(name = goods.goodsName, foodIdx = 0, foodVector = imageVector)) + } catch (e: Exception) { + e.printStackTrace() + } + }.start() + } + } catch (e: Exception) { + e.printStackTrace() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt b/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt index 3eeb5e0..2dc7744 100644 --- a/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt +++ b/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt @@ -96,7 +96,7 @@ object FoodModule { nameScoreList.add(IdNameScore(id = it.id, name = box.get(it.id).name?:"", score = it.score)) } Timber.tag("FoodModule").d("queryFood数据:${nameScoreList.toJsonString()}") - idScoreList.filter { it.score < 0.07 }.forEach { + idScoreList.filter { it.score < 0.05 }.forEach { val food = box.get(it.id) //FoodQueryResult(id = it.id, name = food.name, foodIdx = food.foodIdx, score = it.score) food.name?.let { key -> diff --git a/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt b/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt index 8f56cf3..98640be 100644 --- a/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt +++ b/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt @@ -206,8 +206,8 @@ class CrashHandler private constructor(private val context: Context) : // val crashDir = File(context.getExternalFilesDir(null), CRASH_REPORTS_DIR) val crashDir = File(context.filesDir, CRASH_REPORTS_DIR) - if (!crashDir.exists() && !crashDir.mkdirs()) { - Timber.tag(TAG).e("Failed to create crash report directory") + if (!crashDir.exists()) { + crashDir.mkdirs() return } diff --git a/app/src/main/res/layout/dialog_goods_store.xml b/app/src/main/res/layout/dialog_goods_store.xml index 4cde192..763fa8a 100644 --- a/app/src/main/res/layout/dialog_goods_store.xml +++ b/app/src/main/res/layout/dialog_goods_store.xml @@ -302,15 +302,18 @@ + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="15dp"/> + + + + + diff --git a/app/src/main/res/layout/layout_image_preview.xml b/app/src/main/res/layout/layout_image_preview.xml new file mode 100644 index 0000000..f79208a --- /dev/null +++ b/app/src/main/res/layout/layout_image_preview.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_take_photo.xml b/app/src/main/res/layout/layout_take_photo.xml new file mode 100644 index 0000000..c1a9430 --- /dev/null +++ b/app/src/main/res/layout/layout_take_photo.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +