From 76fa36479238d8aa81f03b840376d0be1d55f8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=A2=9E=E9=A3=9E?= <331023091@qq.com> Date: Fri, 14 Nov 2025 18:13:28 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=94=E8=B0=83=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 + app/src/main/assets/data/class_info.json | 66 ++++---- .../activity/FoodCollectionActivity.kt | 8 +- .../sw/inbound/activity/GoodsListActivity.kt | 153 +++++++++++------- .../com/sw/inbound/dialog/AddGoodsDialog.kt | 83 ++++++---- .../sw/inbound/dialog/CollectSearchDialog.kt | 4 +- .../sw/inbound/dialog/GoodsRecognizeDialog.kt | 4 +- .../com/sw/inbound/dialog/GoodsStoreDialog.kt | 37 +++-- .../com/sw/inbound/dialog/LoadingDialog.kt | 100 ++---------- .../java/com/sw/inbound/objbox/FoodModule.kt | 17 +- .../sw/inbound/repository/RemoteRepository.kt | 17 ++ .../com/sw/inbound/sdk/SensorScaleUtils.kt | 40 +++-- .../com/sw/inbound/utils/BitmapCropper.kt | 8 +- .../java/com/sw/inbound/utils/BitmapSaver.kt | 2 +- .../java/com/sw/inbound/utils/FileUtils.kt | 3 + .../java/com/sw/inbound/utils/ImageUtil.kt | 4 +- .../sw/inbound/viewmodel/ReceiptViewModel.kt | 18 ++- .../main/res/layout/dialog_goods_store.xml | 1 + 18 files changed, 317 insertions(+), 251 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7573d88..8278834 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -153,6 +153,9 @@ dependencies { } else { releaseImplementation("io.objectbox:objectbox-android:$objectboxVersion") } + + implementation("org.greenrobot:eventbus:3.3.1") + } apply(plugin = "io.objectbox") \ No newline at end of file diff --git a/app/src/main/assets/data/class_info.json b/app/src/main/assets/data/class_info.json index 4b169e6..d9b5b22 100644 --- a/app/src/main/assets/data/class_info.json +++ b/app/src/main/assets/data/class_info.json @@ -1,42 +1,42 @@ { "class_names": [ - "圆白菜[卷心菜]", - "大白菜(代表值)", - "大葱", - "洋葱(鲜)[葱头]", - "番茄[西红柿]", - "胡萝卜(红)[金笋,丁香萝卜]", - "芹菜(茎)[旱芹,药芹]", - "茄子(代表值)", - "西兰花[绿菜花]", - "辣椒(青,尖)", - "黄瓜(鲜)[胡瓜]" + "圆白菜[卷心菜,包菜]WP2025111000063", + "大白菜WP2025111000064", + "大葱WP2025111000060", + "洋葱(鲜)[葱头]WP2025111000061", + "番茄WP2025110700016", + "胡萝卜WP2025110600008", + "芹菜WP2025111000065", + "茄子(紫皮,长)WP2025110700024", + "西兰花[绿菜花]WP2025110700029", + "辣椒(青辣椒,螺丝椒)WP2025110700017", + "黄瓜(鲜)[胡瓜]WP2025110700031" ], "class_to_idx": { - "圆白菜[卷心菜]": 0, - "大白菜(代表值)": 1, - "大葱": 2, - "洋葱(鲜)[葱头]": 3, - "番茄[西红柿]": 4, - "胡萝卜(红)[金笋,丁香萝卜]": 5, - "芹菜(茎)[旱芹,药芹]": 6, - "茄子(代表值)": 7, - "西兰花[绿菜花]": 8, - "辣椒(青,尖)": 9, - "黄瓜(鲜)[胡瓜]": 10 + "圆白菜[卷心菜,包菜]WP2025111000063": 0, + "大白菜WP2025111000064": 1, + "大葱WP2025111000060": 2, + "洋葱(鲜)[葱头]WP2025111000061": 3, + "番茄WP2025110700016": 4, + "胡萝卜WP2025110600008": 5, + "芹菜WP2025111000065": 6, + "茄子(紫皮,长)WP2025110700024": 7, + "西兰花[绿菜花]WP2025110700029": 8, + "辣椒(青辣椒,螺丝椒)WP2025110700017": 9, + "黄瓜(鲜)[胡瓜]WP2025110700031": 10 }, "idx_to_class": { - "0": "圆白菜[卷心菜]", - "1": "大白菜(代表值)", - "2": "大葱", - "3": "洋葱(鲜)[葱头]", - "4": "番茄[西红柿]", - "5": "胡萝卜(红)[金笋,丁香萝卜]", - "6": "芹菜(茎)[旱芹,药芹]", - "7": "茄子(代表值)", - "8": "西兰花[绿菜花]", - "9": "辣椒(青,尖)", - "10": "黄瓜(鲜)[胡瓜]" + "0": "圆白菜[卷心菜,包菜]WP2025111000063", + "1": "大白菜WP2025111000064", + "2": "大葱WP2025111000060", + "3": "洋葱(鲜)[葱头]WP2025111000061", + "4": "番茄WP2025110700016", + "5": "胡萝卜WP2025110600008", + "6": "芹菜WP2025111000065", + "7": "茄子(紫皮,长)WP2025110700024", + "8": "西兰花[绿菜花]WP2025110700029", + "9": "辣椒(青辣椒,螺丝椒)WP2025110700017", + "10": "黄瓜(鲜)[胡瓜]WP2025110700031" }, "embedding_dim": 512, "total_images": 770, 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 ef6c6cd..2751ca0 100644 --- a/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt +++ b/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt @@ -276,7 +276,13 @@ class FoodCollectionActivity : ComponentActivity() { private fun image2VectorTask(bitmap: Bitmap, position: Int) { try { initBox() - val imageVector = FoodModule.bitmap2FloatArray(bitmap) + val imageVector = try { + FoodModule.bitmap2FloatArray(bitmap) + } catch (e: Exception) { + e.printStackTrace() + //toast("保存失败") + return + } box?.put( Food( name = searchGoodsList[clickIndex].goodsName, diff --git a/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt b/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt index d11dee9..0143fcb 100644 --- a/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt +++ b/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt @@ -10,6 +10,7 @@ import androidx.activity.viewModels import androidx.camera.view.PreviewView import androidx.core.graphics.toColorInt import androidx.core.view.updateLayoutParams +import androidx.lifecycle.viewModelScope import com.shuwei.intelligent.shelves.utils.ext.appendText import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString import com.sw.inbound.GlobalData @@ -45,13 +46,15 @@ import com.sw.inbound.utils.ext.toJsonString import com.sw.inbound.utils.ext.toast import com.sw.inbound.viewmodel.ReceiptViewModel import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import timber.log.Timber import java.io.File import kotlin.math.abs import kotlin.math.min -typealias RecognizeCallback = (List)->Unit +typealias RecognizeCallback = (List) -> Unit @AndroidEntryPoint abstract class GoodsListActivity : ComponentActivity() { @@ -147,14 +150,16 @@ abstract class GoodsListActivity : ComponentActivity() { startTime = System.currentTimeMillis() binding.root.postDelayed({ SensorScaleUtils.addWeightListener { - try { - weightCallback?.invoke(it) - recognizeWeight(weight = it) - } catch (e: Exception) { - e.printStackTrace() + runOnUiThread { + try { + weightCallback?.invoke(it) + recognizeWeight(weight = it) + } catch (e: Exception) { + e.printStackTrace() + } } } - }, 3 * 1000) + }, 1 * 1000) } private var weightCallback: ((weight: Int) -> Unit)? = null @@ -171,13 +176,13 @@ abstract class GoodsListActivity : ComponentActivity() { // return //} if (weight < 200) { - if (abs(weight) < 10) { - if (DialogManager.getDialogList().size == 1 && - DialogManager.contains("GoodsRecognizeDialog") && - goodsRecognizeDialog?.isShowing == true) { - goodsRecognizeDialog?.dismiss() - } - } +// if (abs(weight) < 10) { +// if (DialogManager.getDialogList().size == 1 && +// DialogManager.contains("GoodsRecognizeDialog") && +// goodsRecognizeDialog?.isShowing == true) { +// goodsRecognizeDialog?.dismiss() +// } +// } return } this.lastWeight = weight @@ -192,7 +197,8 @@ abstract class GoodsListActivity : ComponentActivity() { // Timber.tag(TAG).d("recognizeWeight, checkResult=true") // return // } - Timber.tag(TAG).d("recognizeWeight,recognizeFood:isShowRecognizeDialog=$isShowRecognizeDialog") + Timber.tag(TAG) + .d("recognizeWeight,recognizeFood:isShowRecognizeDialog=$isShowRecognizeDialog") recognizeFood() } @@ -201,19 +207,29 @@ abstract class GoodsListActivity : ComponentActivity() { private val takePhotoSuccessCallback: (Uri) -> Unit = { uri -> Thread { - searchFood(uri) + try { + searchFood(uri) + } catch (e: Exception) { + e.printStackTrace() + } }.start() } fun delayRecognizeFood() { - window.decorView.postDelayed({ + if (abs(lastWeight) < 10) { + return + } + window.decorView.postDelayed( + { recognizeFood() }, - DELAY_TIME.toLong()) + DELAY_TIME.toLong() + ) } + fun recognizeFood() { if (isShowRecognizeDialog.not()) { - if(goodsRecognizeDialog == null) { + if (goodsRecognizeDialog == null) { isShowRecognizeDialog = true } return @@ -231,7 +247,7 @@ abstract class GoodsListActivity : ComponentActivity() { } } - private var recognizeCallback:RecognizeCallback?=null + private var recognizeCallback: RecognizeCallback? = null var isAgainRecognize = false fun againRecognizeFood(callback: RecognizeCallback) { @@ -267,33 +283,47 @@ abstract class GoodsListActivity : ComponentActivity() { targetWidth = 1000, targetHeight = 1300, offsetX = 30, offsetY = 100 ) - val file = BitmapSaver.saveToAppFilesDir( - newBmp, - this, - "IMG_CROP_${System.currentTimeMillis()}.jpg" - ) - Timber.d("${this.javaClass.simpleName}-searchFood-裁剪bitmap保存文件路径:${file?.absolutePath}") - //val foodList = FoodModule.queryFood(newBmp) + if (bitmap.isRecycled.not()) { + bitmap.recycle() + } +// val file = BitmapSaver.saveToAppFilesDir( +// newBmp, +// this, +// "IMG_CROP_${System.currentTimeMillis()}.jpg" +// ) +// Timber.d("${this.javaClass.simpleName}-searchFood-裁剪bitmap保存文件路径:${file?.absolutePath}") + //var foodList = FoodModule.queryFood(newBmp) + //物品编号 + //foodList = foodList.map { "WP"+it.split("WP")[1] } + //物品名称 + //foodList = foodList.map { it.split("WP")[0] } + val foodList = FoodModule.getFoodScoreList(newBmp) - runOnUiThread { - if (foodList.isEmpty()) { - handleGoodsResult() - return@runOnUiThread - } - viewModel.recognizeGoodsList( - //nameList = foodList, - scoreList = foodList, - ) { goodsList -> + if (newBmp.isRecycled.not()) { + newBmp.recycle() + } + if (foodList.isEmpty()) { + recognizeFoodError() + return@let + } + foodList.forEach { + it.name = it.name.split("WP")[0] + } + viewModel.recognizeGoodsList( + //nameList = foodList, + scoreList = foodList, + ) { goodsList -> + runOnUiThread { if (isAgainRecognize) { Loading.dismiss() recognizeCallback?.invoke(goodsList) isAgainRecognize = false - return@recognizeGoodsList + return@runOnUiThread } handleGoodsResult( goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(), - file = file, - name = foodList.joinToString(",") +// file = null, +// name = foodList.joinToString(",") ) } } @@ -302,8 +332,8 @@ abstract class GoodsListActivity : ComponentActivity() { private fun handleGoodsResult( goodsList: List = mutableListOf(), - file: File?=null, - name: String?=null, + file: File? = null, + name: String? = null, ) { runOnUiThread { if (goodsRecognizeDialog?.isShowing == true) { @@ -383,7 +413,8 @@ abstract class GoodsListActivity : ComponentActivity() { val finalWeight = item.goodsWeight?.toDouble().plus2(goods.goodsWeight?.toDouble()) val finalNum = item.receivedNum.plus2(goods.receivedNum) val finalAmount = item.recPriceInItem.plus2(goods.recPriceInItem) - val finalPrice = if (finalAmount == 0.toDouble() || finalNum == 0.toDouble()) 0.toDouble() else finalAmount / finalNum + val finalPrice = + if (finalAmount == 0.toDouble() || finalNum == 0.toDouble()) 0.toDouble() else finalAmount / finalNum item.run { receivedNum = finalNum recUnitPriceTaxIn = finalPrice.roundedDecimalPlace(2) @@ -453,7 +484,10 @@ abstract class GoodsListActivity : ComponentActivity() { val count = goodsList.count { it.isLocalGoods } // 处理返回事件 if (count > 0) { - WarnDialog(context = this@GoodsListActivity, content = "存在未收货的物品,请确认是否放弃收货,若放弃则数据不会保存?") { + WarnDialog( + context = this@GoodsListActivity, + content = "存在未收货的物品,请确认是否放弃收货,若放弃则数据不会保存?" + ) { //onBackPressedDispatcher.onBackPressed() finish() }.show() @@ -531,18 +565,18 @@ abstract class GoodsListActivity : ComponentActivity() { } } - fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) { - viewModel.uploadImage(imageUri) { imgUrl -> - if (imgUrl.isNullOrBlank()) { - callback(null) - return@uploadImage - } - callback(imgUrl) - } - } +// fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) { +// viewModel.uploadImage(imageUri) { imgUrl -> +// if (imgUrl.isNullOrBlank()) { +// callback(null) +// return@uploadImage +// } +// callback(imgUrl) +// } +// } - fun createNewGoods(imageUri: Uri, param: GoodsAddParam, callback: (Boolean) -> Unit) { - viewModel.uploadImage(imageUri) { imgUrl -> + fun createNewGoods(file: File, param: GoodsAddParam, callback: (Boolean) -> Unit) { + viewModel.uploadImage(file) { imgUrl -> if (imgUrl.isNullOrBlank()) { toast("图片上传失败") return@uploadImage @@ -551,4 +585,15 @@ abstract class GoodsListActivity : ComponentActivity() { viewModel.createNewGoods(param = param, callback = callback) } } + + private fun recognizeFoodError() { + if (isAgainRecognize) { + Loading.dismiss() + recognizeCallback?.invoke(mutableListOf()) + isAgainRecognize = false + } else { + handleGoodsResult() + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/dialog/AddGoodsDialog.kt b/app/src/main/java/com/sw/inbound/dialog/AddGoodsDialog.kt index 0f8ecb4..80a0875 100644 --- a/app/src/main/java/com/sw/inbound/dialog/AddGoodsDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/AddGoodsDialog.kt @@ -19,7 +19,10 @@ import com.sw.inbound.ext.toSafeBigDecimal import com.sw.inbound.ext.toSafeFloat import com.sw.inbound.model.request.GoodsAddParam import com.sw.inbound.model.response.DictType +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.toast @@ -46,6 +49,7 @@ class AddGoodsDialog( private val cameraUtils: CameraUtils by lazy { CameraUtils(activity!!) } + override fun show() { super.show() cameraUtils.setPreviewController(previewView) @@ -71,7 +75,10 @@ class AddGoodsDialog( } cameraUtils.initCamera() val previewBinding = - LayoutCameraPreviewBinding.inflate(LayoutInflater.from(context), binding.flCameraPreview) + LayoutCameraPreviewBinding.inflate( + LayoutInflater.from(context), + binding.flCameraPreview + ) previewBinding.previewView.let { it.updateLayoutParams { width = 428.dp @@ -98,9 +105,9 @@ class AddGoodsDialog( cameraUtils.takePhoto(takePhotoCallback) } binding.btnUploadImg.gone() - binding.btnUploadImg.setOnClickListener { - uploadImage() - } +// binding.btnUploadImg.setOnClickListener { +// uploadImage() +// } binding.tvGoodsType.let { tv -> tv.text = "原材料" tv.tag = GlobalData.goodsTypeList.firstOrNull { it.value == "原材料" }?.id @@ -111,7 +118,7 @@ class AddGoodsDialog( textView = binding.tvProcurementUnit, arrowImage = binding.ivProcurementArrow, list = GlobalData.unitTypeList, - height = 2*71.dp + height = 2 * 71.dp ) // showDropDownList( // binding.flGoodsType, @@ -129,7 +136,7 @@ class AddGoodsDialog( textView = binding.tvWarehouseUnit, arrowImage = binding.ivWarehouseArrow, list = GlobalData.unitTypeList, - height = 3*71.dp + height = 3 * 71.dp ) { binding.tvSelectUseUnit.text = it.value binding.tvSelectProcurementUnit.text = it.value @@ -144,7 +151,7 @@ class AddGoodsDialog( height: Int = 355.dp, block: (DictType) -> Unit = {} ) { - dropdownView.setOnClickListener {v-> + dropdownView.setOnClickListener { v -> dropdownList.clear() val tempList = list.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() } @@ -238,31 +245,51 @@ class AddGoodsDialog( purchaseValue = goodsCount.toSafeFloat(), purchasePrice = goodsPrice.toSafeBigDecimal(), ) - activity?.createNewGoods(imageUri!!, param) { - if (it.not()) { - context.toast("新增物品失败") - return@createNewGoods + activity?.let { + Loading.show(it) + } + ImageUtil.uriToBitmap(context, imageUri!!)?.let { bitmap -> + val newBmp = BitmapCropper.cropCenter( + original = bitmap, + targetWidth = 1000, targetHeight = 1300, + offsetX = 30, offsetY = 100 + ) + val file = BitmapSaver.saveToAppFilesDir( + newBmp, + context, + "IMG_CROP_${System.currentTimeMillis()}.jpg" + ) + if(file == null) { + context.toast("请重新拍照后再试") + Loading.dismiss() + return@let + } + activity?.createNewGoods(file, param) { + Loading.dismiss() + if (it.not()) { + context.toast("新增物品失败") + return@createNewGoods + } + context.toast("新增物品成功") + confirmBlock(goodsName) + dismiss() } - context.toast("新增物品成功") - confirmBlock(goodsName) - dismiss() } } private var imageUri: Uri? = null - private fun uploadImage() { - if (imageUri == null) { - context.toast("请采集图片") - return - } - activity?.uploadImage(imageUri!!) { imgUrl -> - if (imgUrl.isNullOrBlank()) { - context.toast("图片上传失败") - return@uploadImage - } - context.toast(imgUrl) - } - } - +// private fun uploadImage() { +// if (imageUri == null) { +// context.toast("请采集图片") +// return +// } +// activity?.uploadImage(imageUri!!) { imgUrl -> +// if (imgUrl.isNullOrBlank()) { +// context.toast("图片上传失败") +// return@uploadImage +// } +// context.toast(imgUrl) +// } +// } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/dialog/CollectSearchDialog.kt b/app/src/main/java/com/sw/inbound/dialog/CollectSearchDialog.kt index 0f978b1..6651ad7 100644 --- a/app/src/main/java/com/sw/inbound/dialog/CollectSearchDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/CollectSearchDialog.kt @@ -151,7 +151,7 @@ class CollectSearchDialog( confirmBlock = { Thread { activity?.runOnUiThread { - Loading.show(context) + Loading.show(activity!!) } val name = list[position].goodsName val filterIdList = box?.all?.filter { it.name == name }?.map { it.id } @@ -191,7 +191,7 @@ class CollectSearchDialog( list.clear() var queryList = box?.all?.distinctBy { it.name } if (searchName.isNullOrBlank().not()) { - queryList = queryList?.filter { it.name?.contains(searchName) == true } + queryList = queryList?.filter { it.name?.contains(searchName!!) == true } } queryList?.forEach { list.add((SearchGoodsInfo.Record(goodsName = it.name))) 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 1eb4558..83d677d 100644 --- a/app/src/main/java/com/sw/inbound/dialog/GoodsRecognizeDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/GoodsRecognizeDialog.kt @@ -88,14 +88,14 @@ class GoodsRecognizeDialog( binding.btnAgainRecognize.setOnClickListener { //dismiss() activity?.againRecognizeFood { goodsList -> + binding.rvRecognize.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) list.clear() list.addAll(goodsList) + recognizeAdapter.notifyDataSetChanged() if (recognizeAdapter.list.isEmpty()) { loadEmptyView() return@againRecognizeFood } - binding.rvRecognize.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - recognizeAdapter.notifyDataSetChanged() } } } 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 ace9c1a..9178c21 100644 --- a/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt @@ -10,7 +10,6 @@ import android.text.style.StyleSpan import android.view.LayoutInflater import android.view.View import android.widget.EditText -import android.widget.FrameLayout import android.widget.LinearLayout import androidx.camera.view.PreviewView import androidx.core.graphics.toColorInt @@ -25,7 +24,6 @@ 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 @@ -97,6 +95,9 @@ class GoodsStoreDialog( binding.btnConfirm.setOnClickListener { confirmInputData() } + binding.tvTitle.setOnClickListener { + SensorScaleUtils.startScale(autoScale = true) + } // binding.ivAddUnit.setOnClickListener { // AddProcurementUnitDialog(context).show() // } @@ -124,13 +125,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(",") - .append("1").append(goods.kcUnitName).append("=") - .append(first.consumeValue).append("克") + val stringBuilder = + StringBuilder().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("克") binding.tvUnitCalculate.text = stringBuilder.toString() //val count = getUnitCount(dictType.id!!) //if (count.isBlank() || "0" == count) { @@ -268,9 +268,7 @@ class GoodsStoreDialog( StyleSpan(Typeface.BOLD) ) appendText( - " 克", - ForegroundColorSpan("#FF000033".toColorInt()), - StyleSpan(Typeface.BOLD) + " 克", ForegroundColorSpan("#FF000033".toColorInt()), StyleSpan(Typeface.BOLD) ) } } @@ -375,6 +373,9 @@ class GoodsStoreDialog( } } } + binding.root.postDelayed({ + SensorScaleUtils.startScale() + }, 2600) } private var imageUri: Uri? = null @@ -435,8 +436,10 @@ class GoodsStoreDialog( ImageUtil.uriToBitmap(context, imageUri!!)?.let { bitmap -> val cropBitmap = BitmapCropper.cropCenter( original = bitmap, - targetWidth = 1000, targetHeight = 1300, - offsetX = 30, offsetY = 100 + targetWidth = 1000, + targetHeight = 1300, + offsetX = 30, + offsetY = 100 ) val file = BitmapSaver.saveToAppFilesDir( cropBitmap, context, "IMG_CROP_${System.currentTimeMillis()}.jpg" @@ -448,7 +451,11 @@ class GoodsStoreDialog( Thread { try { val imageVector = FoodModule.bitmap2FloatArray(bitmap) - box?.put(Food(name = goods.goodsName, foodIdx = 0, foodVector = imageVector)) + box?.put( + Food( + name = goods.goodsName, foodIdx = 0, foodVector = imageVector + ) + ) } catch (e: Exception) { e.printStackTrace() } diff --git a/app/src/main/java/com/sw/inbound/dialog/LoadingDialog.kt b/app/src/main/java/com/sw/inbound/dialog/LoadingDialog.kt index 5c1b88c..ee3b8b1 100644 --- a/app/src/main/java/com/sw/inbound/dialog/LoadingDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/LoadingDialog.kt @@ -1,26 +1,30 @@ package com.sw.inbound.dialog +import android.app.Activity import android.app.Dialog import android.content.Context import android.graphics.Color import android.view.LayoutInflater -import android.view.WindowManager import androidx.core.graphics.drawable.toDrawable import com.sw.inbound.R import com.sw.inbound.databinding.DialogLoadingBinding +import kotlin.let +import kotlin.run object Loading { private var dialog: LoadingDialog? = null - fun show(context: Context) { + fun show(activity: Activity) { try { + if (activity.isFinishing || activity.isDestroyed) { + return + } if (dialog?.isShowing == true) { dialog?.dismiss() } - if (dialog == null) { - dialog = LoadingDialog(context) + dialog = LoadingDialog(activity) } dialog?.show() } catch (e: Exception) { @@ -56,10 +60,10 @@ class LoadingDialog( setCanceledOnTouchOutside(true) window?.run { setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) - //setFlags( - // WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, - // WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - //) +// setFlags( +// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, +// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE +// ) } setOnDismissListener { onDismiss() @@ -67,83 +71,3 @@ class LoadingDialog( } } -//class LoadingDialog3( -// private val activity: Activity, -// private val message: String = "加载中……", -// private val onDismiss: () -> Unit = {} -//) : DialogFragment() { -// -// override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { -// return SafeDialog( -// activity = activity, -// themeResId = R.style.ToastDialogTheme, -// ).apply { -// val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context)) -// binding.tvMessage.text = message -// setContentView(binding.root) -// setCancelable(true) -// window?.run { -// setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) -// setFlags( -// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, -// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE -// ); -// } -// setOnDismissListener { -// onDismiss() -// } -// } -// } -// -// override fun dismiss() { -// super.dismiss() -// } -// -// override fun show(manager: FragmentManager, tag: String?) { -// runCatching { -// super.show(manager, tag) -// Handler(Looper.getMainLooper()).postDelayed({ -// super.dismiss() -// }, 800) -// }.onFailure { -// it.printStackTrace() -// } -// } -// -//} - -//class LoadingDialog( -// private val activity: Activity, -// private val message: String = "加载中……", -// private val onDismiss: () -> Unit = {} -//) : SafeDialog( -// activity = activity, -// themeResId = R.style.ToastDialogTheme, -//) { -// -// override fun onCreate(savedInstanceState: Bundle?) { -// super.onCreate(savedInstanceState) -// val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context)) -// binding.tvMessage.text = message -// setContentView(binding.root) -// setCancelable(true) -// window?.run { -// setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) -// setFlags( -// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, -// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE -// ); -// } -// setOnDismissListener { -// onDismiss() -// } -// } -// -// fun show(manager: FragmentManager, tag: String?) { -// show() -// Handler(Looper.getMainLooper()).postDelayed({ -// super.dismiss() -// }, 800) -// } -// -//} 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 f830c9c..53e2932 100644 --- a/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt +++ b/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt @@ -61,14 +61,8 @@ object FoodModule { NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB ) val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor() +// return floatArrayOf() val floatArray = outputTensor.dataAsFloatArray -// try { -// if (bitmap.isRecycled.not()) { -// bitmap.recycle() -// } -// } catch (e: Exception) { -// e.printStackTrace() -// } return floatArray } @@ -110,8 +104,13 @@ object FoodModule { } fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List { val floatArray = bitmap2FloatArray(bitmap) +// return emptyList() val nameScoreList = queryFoodNameScore(floatArray, queryCount) - val maxScoreList = nameScoreList.groupBy { it.name }.map { (_, value) -> value.minByOrNull { it.score }!! }.toMutableList() + val maxScoreList = nameScoreList + .filter { it.score < 0.20 } + .groupBy { it.name } + .map { (_, value) -> value.minByOrNull { it.score }!! } + .toMutableList() val map = mutableMapOf() nameScoreList.forEach { val key = it.name @@ -142,7 +141,7 @@ object FoodModule { data class IdNameScore( val id:Long, - val name:String, + var name:String, val score: Double ) diff --git a/app/src/main/java/com/sw/inbound/repository/RemoteRepository.kt b/app/src/main/java/com/sw/inbound/repository/RemoteRepository.kt index 8b87e36..325434b 100644 --- a/app/src/main/java/com/sw/inbound/repository/RemoteRepository.kt +++ b/app/src/main/java/com/sw/inbound/repository/RemoteRepository.kt @@ -20,6 +20,7 @@ import com.sw.inbound.network.api.ApiService import com.sw.inbound.utils.ContextUtils import com.sw.inbound.utils.FileUtils import timber.log.Timber +import java.io.File import javax.inject.Inject /** @@ -126,6 +127,22 @@ class RemoteRepository @Inject constructor( } } } + suspend fun uploadImage(file:File): ApiResponse { + return safeApiCall { + //val codeRequestBody = RequestBody.create( + // MultipartBody.FORM, + // "4" + //) + + val part = FileUtils.genRequestPart(file) + if (part == null) { + ApiResponse(code = "-1", msg = "解析图片失败") + } else { + //apiService.uploadImage(code = codeRequestBody, file = part) + apiService.uploadImage(file = part) + } + } + } /** * 部分收货 diff --git a/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt b/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt index 522d56a..67c4789 100644 --- a/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt +++ b/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt @@ -2,12 +2,17 @@ package com.sw.inbound.sdk import android.os.Handler import android.os.Looper +import com.sw.inbound.utils.MessageEvent +import com.sw.inbound.utils.ThreadUtils import com.sw.inbound.utils.ToastUtils import com.wabon.wbintelligenthardwaresdk.api.SensorScale import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult +import kotlinx.coroutines.delay +import org.greenrobot.eventbus.EventBus import timber.log.Timber import kotlin.math.roundToInt + typealias WeightCallback = (Int) -> Unit /** @@ -18,18 +23,24 @@ object SensorScaleUtils { const val serialPort = "/dev/ttyS7" const val baudRate = 115200 private var mSensorScale: SensorScale? = null + var isValidWeight = false private fun init() { + if (mSensorScale != null) { + return + } mSensorScale = SensorScale(object : OnScaleResult { /** * 读取重量 */ override fun readWeight(state: Int, value: Double) { - Handler(Looper.getMainLooper()).post { - callbackList.forEach { - it.invoke((value * 1000).roundToInt()) - } + isValidWeight = true + callbackList.forEach { + it.invoke((value * 1000).roundToInt()) } + +// EventBus.getDefault().post(MessageEvent((value * 1000).roundToInt())) + } /** @@ -40,9 +51,11 @@ object SensorScaleUtils { } override fun fail(errCode: Int) { + isValidWeight = false Timber.e("fail code = $errCode") Handler(Looper.getMainLooper()).post { ToastUtils.showToast("秤读取数据异常") + startScale() } } }) @@ -61,15 +74,16 @@ object SensorScaleUtils { init() mSensorScale?.openScale(serialPort, baudRate) { open -> if (open && autoScale) { - Handler(Looper.getMainLooper()).postDelayed({ - mSensorScale?.readWeight() - mSensorScale?.startContinuousRead() - }, 1500) -// ThreadUtils.launchOnIo { -// delay(1000) -// // 打开后需要等待后才能调用,否则会 1001 SDK未初始化 -// mSensorScale?.startContinuousRead() -// } +// Handler(Looper.getMainLooper()).postDelayed({ +// mSensorScale?.readWeight() +// mSensorScale?.startContinuousRead() +// }, 1500) + ThreadUtils.launchOnIo { + delay(1000) + // 打开后需要等待后才能调用,否则会 1001 SDK未初始化 + mSensorScale?.readWeight() + mSensorScale?.startContinuousRead() + } } } } diff --git a/app/src/main/java/com/sw/inbound/utils/BitmapCropper.kt b/app/src/main/java/com/sw/inbound/utils/BitmapCropper.kt index fff888e..cf9c70c 100644 --- a/app/src/main/java/com/sw/inbound/utils/BitmapCropper.kt +++ b/app/src/main/java/com/sw/inbound/utils/BitmapCropper.kt @@ -1,5 +1,6 @@ package com.sw.inbound.utils import android.graphics.Bitmap +import android.util.DisplayMetrics object BitmapCropper { /** @@ -22,8 +23,11 @@ object BitmapCropper { startY = startY.coerceAtLeast(0) val actualWidth = minOf(targetWidth, originalWidth - startX) val actualHeight = minOf(targetHeight, originalHeight - startY) - - return Bitmap.createBitmap(original, startX, startY, actualWidth, actualHeight) + + return Bitmap.createBitmap(original, startX, startY, actualWidth, actualHeight).also { +// it.setConfig(Bitmap.Config.RGB_565) +// it.density = DisplayMetrics.DENSITY_LOW + } } } diff --git a/app/src/main/java/com/sw/inbound/utils/BitmapSaver.kt b/app/src/main/java/com/sw/inbound/utils/BitmapSaver.kt index c8b1d83..b6c938d 100644 --- a/app/src/main/java/com/sw/inbound/utils/BitmapSaver.kt +++ b/app/src/main/java/com/sw/inbound/utils/BitmapSaver.kt @@ -27,7 +27,7 @@ object BitmapSaver { context: Context, fileName: String, format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG, - quality: Int = 100 + quality: Int = 10 ): File? { //val dir = context.getExternalFilesDir(null) val dir = context.cacheDir diff --git a/app/src/main/java/com/sw/inbound/utils/FileUtils.kt b/app/src/main/java/com/sw/inbound/utils/FileUtils.kt index d8191da..00da3c3 100644 --- a/app/src/main/java/com/sw/inbound/utils/FileUtils.kt +++ b/app/src/main/java/com/sw/inbound/utils/FileUtils.kt @@ -51,6 +51,9 @@ object FileUtils { Timber.d("genRequestPart imageUri = $imageUri") // 1. 从Uri获取文件 val file = getFileFromUri(context, imageUri) + return genRequestPart(file) + } + fun genRequestPart(file: File?): MultipartBody.Part? { if (file == null) { Timber.e("getFileFromUri file is null") return null diff --git a/app/src/main/java/com/sw/inbound/utils/ImageUtil.kt b/app/src/main/java/com/sw/inbound/utils/ImageUtil.kt index 8d8b1a3..edd012c 100644 --- a/app/src/main/java/com/sw/inbound/utils/ImageUtil.kt +++ b/app/src/main/java/com/sw/inbound/utils/ImageUtil.kt @@ -6,9 +6,11 @@ import android.graphics.BitmapFactory import android.net.Uri object ImageUtil { - fun uriToBitmap(context: Context, uri: Uri): Bitmap? { return try { + val options = BitmapFactory.Options() + options.inSampleSize = 10; // 这会将图片的尺寸缩小到原来的1/2 + options.inPreferredConfig = Bitmap.Config.RGB_565 context.contentResolver.openInputStream(uri)?.use { stream -> BitmapFactory.decodeStream(stream) } diff --git a/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt index 57c8a53..7eff3a2 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt @@ -10,6 +10,7 @@ import com.sw.inbound.repository.RemoteRepository import com.sw.inbound.utils.ext.toJsonString import dagger.hilt.android.lifecycle.HiltViewModel import timber.log.Timber +import java.io.File import javax.inject.Inject /** @@ -335,9 +336,20 @@ class ReceiptViewModel @Inject constructor( } } - fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) { +// fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) { +// launchWithLoading { +// val resp = repository.uploadImage(imageUri) +// if (!parseResponse(resp)) { +// callback(null) +// return@launchWithLoading +// } +// callback(resp.data) +// } +// } + + fun uploadImage(file:File, callback: (String?) -> Unit) { launchWithLoading { - val resp = repository.uploadImage(imageUri) + val resp = repository.uploadImage(file) if (!parseResponse(resp)) { callback(null) return@launchWithLoading @@ -365,4 +377,6 @@ class ReceiptViewModel @Inject constructor( callback(true) } } + + } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_goods_store.xml b/app/src/main/res/layout/dialog_goods_store.xml index ac11f0a..960cb6f 100644 --- a/app/src/main/res/layout/dialog_goods_store.xml +++ b/app/src/main/res/layout/dialog_goods_store.xml @@ -10,6 +10,7 @@ tools:ignore="HardcodedText">