优化-待测试

This commit is contained in:
2025-12-01 12:05:39 +08:00
parent 46bfb3faac
commit 1c40491819
10 changed files with 448 additions and 162 deletions
@@ -1,13 +1,18 @@
package com.sw.inbound.activity package com.sw.inbound.activity
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.widget.TextView
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.inbound.R import com.sw.inbound.R
@@ -17,6 +22,7 @@ import com.sw.inbound.databinding.ActivityFoodCollectionBinding
import com.sw.inbound.databinding.LayoutCameraPreviewBinding import com.sw.inbound.databinding.LayoutCameraPreviewBinding
import com.sw.inbound.databinding.LayoutEmptySearchBinding import com.sw.inbound.databinding.LayoutEmptySearchBinding
import com.sw.inbound.dialog.CollectSearchDialog import com.sw.inbound.dialog.CollectSearchDialog
import com.sw.inbound.dialog.CustomDialog
import com.sw.inbound.dialog.Loading import com.sw.inbound.dialog.Loading
import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.objbox.Food import com.sw.inbound.objbox.Food
@@ -26,6 +32,7 @@ import com.sw.inbound.objbox.ObjectBox
import com.sw.inbound.utils.BitmapCropper import com.sw.inbound.utils.BitmapCropper
import com.sw.inbound.utils.BitmapSaver import com.sw.inbound.utils.BitmapSaver
import com.sw.inbound.utils.CameraUtils import com.sw.inbound.utils.CameraUtils
import com.sw.inbound.utils.ImageUploader
import com.sw.inbound.utils.ImageUtil import com.sw.inbound.utils.ImageUtil
import com.sw.inbound.utils.ext.addOnActionSearchListener import com.sw.inbound.utils.ext.addOnActionSearchListener
import com.sw.inbound.utils.ext.clickWithDebounce import com.sw.inbound.utils.ext.clickWithDebounce
@@ -41,7 +48,10 @@ import com.sw.inbound.viewmodel.ReceiptViewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.objectbox.Box import io.objectbox.Box
import io.objectbox.kotlin.boxFor import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@@ -77,8 +87,8 @@ class FoodCollectionActivity : ComponentActivity() {
it.uploadSuccess = false it.uploadSuccess = false
} }
collectionAdapter.notifyItemChanged(position) collectionAdapter.notifyItemChanged(position)
val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() } val count = collectList.count { it.imageFile != null && it.uploadSuccess.not() }
binding.btnUploadImage.text = "待上传图片${count}" // binding.btnUploadImage.text = "待上传图片${count}张"
} }
} }
} }
@@ -135,14 +145,14 @@ class FoodCollectionActivity : ComponentActivity() {
searchGoods() searchGoods()
} }
} }
binding.btnUploadImage.setOnClickListener { // binding.btnUploadImage.setOnClickListener {
val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() } // val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() }
if (count == 0) { // if (count == 0) {
toast("已全部上传成功") // toast("已全部上传成功")
return@setOnClickListener // return@setOnClickListener
} // }
uploadAllImage() // uploadAllImage()
} // }
binding.btnSave.setOnClickListener { _ -> binding.btnSave.setOnClickListener { _ ->
if (clickIndex == -1) { if (clickIndex == -1) {
toast("请选择物品名称") toast("请选择物品名称")
@@ -153,8 +163,10 @@ class FoodCollectionActivity : ComponentActivity() {
toast("请拍摄物品照片") toast("请拍摄物品照片")
return@setOnClickListener return@setOnClickListener
} }
vectorThread() // vectorThread()
uploadAllImage() // uploadAllImage()
upload()
} }
binding.btnTakePhoto.clickWithDebounce { binding.btnTakePhoto.clickWithDebounce {
takePhoto() takePhoto()
@@ -182,7 +194,7 @@ class FoodCollectionActivity : ComponentActivity() {
loadEmptyView() loadEmptyView()
binding.tvTitle.setOnClickListener { binding.tvTitle.setOnClickListener {
startActivity<LocalImagePreviewActivity> { } startActivity<LocalImagePreviewActivity> { }
// val goodsImage = GoodsImage(goodsId = "1993493094888140802", goodsName = "多宝鱼", startTime = 1764120531856L, endTime = 1764121842825L) // val goodsImage = GoodsImage(goodsId = "1993493094888140802", goodsName = "多宝鱼", startTime = 1764120531856L, endTime = 1764121842825L)
// uploadImage(goodsImage) // uploadImage(goodsImage)
@@ -261,14 +273,14 @@ class FoodCollectionActivity : ComponentActivity() {
searchAdapter.notifyDataSetChanged() searchAdapter.notifyDataSetChanged()
loadEmptyView() loadEmptyView()
binding.ivFinish.invisible() binding.ivFinish.invisible()
binding.btnUploadImage.text = "待上传图片${0}" // binding.btnUploadImage.text = "待上传图片${0}张"
} }
private val cameraCallback: (Uri) -> Unit = { uri -> private val cameraCallback: (Uri) -> Unit = { uri ->
val index = collectList.indexOfFirst { it.imageFile == null } val index = collectList.indexOfFirst { it.imageFile == null }
if (index == -1) { if (index == -1) {
toast("每次只允许保存6条数据") toast("每次只允许保存6条数据")
rerurn@cameraCallback rerurn@ cameraCallback
} }
try { try {
ImageUtil.uriToBitmap(this, uri)?.let { bitmap -> ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
@@ -286,7 +298,8 @@ class FoodCollectionActivity : ComponentActivity() {
return@let return@let
} }
val foodList = FoodModule.queryFoodNameScore(imageVector) val foodList = FoodModule.queryFoodNameScore(imageVector)
val filterList = foodList.filter { it.score < FoodModule.BAG_RATE && it.name.contains("黑袋子")} val filterList =
foodList.filter { it.score < FoodModule.BAG_RATE && it.name.contains("黑袋子") }
if (filterList.isNotEmpty()) { if (filterList.isNotEmpty()) {
toast("当前物品可能被袋子遮挡,请检查后重试") toast("当前物品可能被袋子遮挡,请检查后重试")
return@let return@let
@@ -302,8 +315,8 @@ class FoodCollectionActivity : ComponentActivity() {
it.isShowCamera = false it.isShowCamera = false
} }
collectionAdapter.notifyItemChanged(index) collectionAdapter.notifyItemChanged(index)
val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() } val count = collectList.count { it.imageFile != null && it.uploadSuccess.not() }
binding.btnUploadImage.text = "待上传图片${count}" // binding.btnUploadImage.text = "待上传图片${count}张"
if (cropBitmap.isRecycled.not()) { if (cropBitmap.isRecycled.not()) {
cropBitmap.recycle() cropBitmap.recycle()
} }
@@ -337,9 +350,10 @@ class FoodCollectionActivity : ComponentActivity() {
} }
private fun image2VectorTask( private fun image2VectorTask(
bitmap: Bitmap?=null, bitmap: Bitmap? = null,
imageVector: FloatArray?=null, imageVector: FloatArray? = null,
position: Int) { position: Int
) {
try { try {
initBox() initBox()
// val imageVector = try { // val imageVector = try {
@@ -443,51 +457,77 @@ class FoodCollectionActivity : ComponentActivity() {
} }
} }
// private val failList = mutableListOf<File>() // private fun uploadAllImage() {
// private var successCount = 0 // Loading.show(this)
private fun uploadAllImage() { // val files = collectList.filter { it.imageFile!=null }.map { it.imageFile!! }
Loading.show(this) // if (files.isEmpty()) {
val files = collectList.filter { it.imageFile!=null }.map { it.imageFile!! } // return
if (files.isEmpty()) { // }
return // val goods = searchGoodsList[clickIndex]
} // for (index in collectList.indices step 5) {
// successCount = 0 // val end = if(index + 5 < collectList.size - 1) index + 5 else collectList.size - 1
// failList.clear() // val subList = collectList.subList(index, end)
val goods = searchGoodsList[clickIndex] // val subFiles = subList.map { it.imageFile }
for (index in collectList.indices step 5) { // viewModel.uploadMultipleImages(goods.id!!, goods.goodsName!!, subFiles) {isSuccess->
val end = if(index + 5 < collectList.size - 1) index + 5 else collectList.size - 1 // Timber.tag(TAG).d("uploadMultipleImages: ${isSuccess}")
val subList = collectList.subList(index, end) // subList.filter { it.imageFile!=null }.forEach { it.uploadSuccess = isSuccess }
val subFiles = subList.map { it.imageFile } //
viewModel.uploadMultipleImages(goods.id!!, goods.goodsName!!, subFiles) {isSuccess-> // val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() }
Timber.tag(TAG).d("uploadMultipleImages: ${isSuccess}") // runOnUiThread {
//{"code":"00000","data":null,"msg":"成功","total":0} // binding.btnUploadImage.text = "待上传图片${count}张"
// val resp = result?.toObject<RespData>() // if (count == 0) {
// val isSuccess = resp?.code == "00000" // Loading.dismiss()
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()
}
}
// binding.ivFinish.run {
// if (isSuccess) visible() else invisible()
// } // }
} // }
// }
private fun upload() {
lifecycleScope.launch {
val totalFileCount = collectList.count { it.imageFile != null }
val goods = searchGoodsList[clickIndex]
val params = HashMap<String, RequestBody>()
//params["placeId"] = restId.toRequestBody()
params["foodId"] = goods.id!!.toRequestBody()
params["foodName"] = goods.goodsName!!.toRequestBody()
//params["foodVector"] = foodVector.toRequestBody()
ImageUploader(
totalList = collectList,
uploadImage = { batch ->
val files = batch.map { it.imageFile }
viewModel.uploadMultipleImages(files = files, params)
},
onProgress = { count, batch ->
runOnUiThread {
showWaitingDialog2("图片上传中$count/$totalFileCount")
batch.forEach {
it.uploadSuccess = true
}
}
},
onError = {
runOnUiThread {
hideWaitingDialog()
toast("上传失败,请稍后重试")
}
},
onComplete = {
hideWaitingDialog()
vectorThread()
}
).processUploads()
} }
} }
private val receiptViewModel: ReceiptViewModel by viewModels() private val receiptViewModel: ReceiptViewModel by viewModels()
fun searchGoodsInfoList(goodsName: String, block:(List<SearchGoodsInfo.Record>)->Unit) { fun searchGoodsInfoList(goodsName: String, block: (List<SearchGoodsInfo.Record>) -> Unit) {
runBlocking { runBlocking {
val list = searchGoodsInfoList2(goodsName) val list = searchGoodsInfoList2(goodsName)
block(list) block(list)
} }
} }
suspend fun searchGoodsInfoList2( suspend fun searchGoodsInfoList2(
goodsName: String, goodsName: String,
pageNo: Int = 1, pageNo: Int = 1,
@@ -496,18 +536,53 @@ class FoodCollectionActivity : ComponentActivity() {
return receiptViewModel.searchGoodsInfoList2(goodsName, pageNo, pageSize) return receiptViewModel.searchGoodsInfoList2(goodsName, pageNo, pageSize)
} }
private var mDialogWaiting: CustomDialog? = null
/**
* 显示等待提示框
*/
fun showWaitingDialog(tip: String?): Dialog? {
hideWaitingDialog()
val view = View.inflate(this, R.layout.dialog_waiting, null)
if (!TextUtils.isEmpty(tip)) (view.findViewById<View?>(R.id.tvTip) as TextView).text = tip
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show()
mDialogWaiting!!.setCancelable(true)
return mDialogWaiting
}
/**
* 隐藏等待提示框
*/
fun hideWaitingDialog() {
mDialogWaiting?.dismiss()
mDialogWaiting = null
}
fun showWaitingDialog2(tip: String?) {
if (mDialogWaiting == null) {
hideWaitingDialog()
val view = View.inflate(this, R.layout.dialog_waiting, null)
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show()
mDialogWaiting!!.setCancelable(true)
}
val tvTip = findViewById<TextView>(R.id.tvTip)
tvTip.text = tip
}
data class RespData( data class RespData(
var code:String?=null, var code: String? = null,
var data:String?=null, var data: String? = null,
var msg:String?=null, var msg: String? = null,
) )
data class GoodsImage( data class GoodsImage(
var goodsId:String, var goodsId: String,
var goodsName:String, var goodsName: String,
var startTime:Long, var startTime: Long,
var endTime:Long var endTime: Long
) )
// //
// val goodsImageList = mutableListOf<GoodsImage>().apply { // val goodsImageList = mutableListOf<GoodsImage>().apply {
@@ -563,53 +638,53 @@ class FoodCollectionActivity : ComponentActivity() {
// endTime = 1763696990541L // endTime = 1763696990541L
// )) // ))
// } // }
private fun uploadImage(goodsImage: GoodsImage) { // private fun uploadImage(goodsImage: GoodsImage) {
Loading.show(this) // Loading.show(this)
val cropFile = File(this.cacheDir, "crop") // val cropFile = File(this.cacheDir, "crop")
val list = mutableListOf<File>() // val list = mutableListOf<File>()
val startTime = goodsImage.startTime // val startTime = goodsImage.startTime
val endTime = goodsImage.endTime // val endTime = goodsImage.endTime
cropFile.listFiles()?.forEach { // cropFile.listFiles()?.forEach {
if (it.isDirectory) { // if (it.isDirectory) {
return@forEach // return@forEach
} // }
val start = "IMG_CROP_".length // val start = "IMG_CROP_".length
val end = it.name.indexOf(".jpg") // val end = it.name.indexOf(".jpg")
val time = it.name.substring(start, end).toLong() // val time = it.name.substring(start, end).toLong()
if (time in startTime..endTime) { // if (time in startTime..endTime) {
list.add(it) // list.add(it)
} // }
if (list.size < 5) { // if (list.size < 5) {
return@forEach // return@forEach
} // }
viewModel.uploadMultipleImages( // viewModel.uploadMultipleImages(
goodsId = goodsImage.goodsId, // goodsId = goodsImage.goodsId,
goodsName = goodsImage.goodsName, // goodsName = goodsImage.goodsName,
files = list // files = list
) { isSuccess -> // ) { isSuccess ->
// val resp = data?.toObject<RespData>() //// val resp = data?.toObject<RespData>()
// val isSuccess = resp?.code == "00000" //// val isSuccess = resp?.code == "00000"
binding.ivFinish.run { // binding.ivFinish.run {
if (isSuccess) visible() else invisible() // if (isSuccess) visible() else invisible()
} // }
} // }
list.clear() // list.clear()
} // }
if (list.isNotEmpty()) { // if (list.isNotEmpty()) {
viewModel.uploadMultipleImages( // viewModel.uploadMultipleImages(
goodsId = goodsImage.goodsId, // goodsId = goodsImage.goodsId,
goodsName = goodsImage.goodsName, // goodsName = goodsImage.goodsName,
files = list // files = list
) { isSuccess -> // ) { isSuccess ->
// val resp = data?.toObject<RespData>() //// val resp = data?.toObject<RespData>()
// val isSuccess = resp?.code == "00000" //// val isSuccess = resp?.code == "00000"
binding.ivFinish.run { // binding.ivFinish.run {
if (isSuccess) visible() else invisible() // if (isSuccess) visible() else invisible()
} // }
} // }
} // }
Loading.dismiss() // Loading.dismiss()
} // }
} }
@@ -10,6 +10,7 @@ import androidx.activity.viewModels
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.shuwei.intelligent.shelves.utils.ext.appendText import com.shuwei.intelligent.shelves.utils.ext.appendText
import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString
@@ -45,7 +46,10 @@ import com.sw.inbound.utils.ext.toJsonString
import com.sw.inbound.utils.ext.toast import com.sw.inbound.utils.ext.toast
import com.sw.inbound.viewmodel.ReceiptViewModel import com.sw.inbound.viewmodel.ReceiptViewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import kotlin.math.abs import kotlin.math.abs
@@ -180,8 +184,9 @@ abstract class GoodsListActivity : ComponentActivity() {
// Timber.tag(TAG).d(clazzName) // Timber.tag(TAG).d(clazzName)
if (DialogManager.getDialogList().size == 1 && if (DialogManager.getDialogList().size == 1 &&
DialogManager.contains("GoodsRecognizeDialog") && DialogManager.contains("GoodsRecognizeDialog") &&
goodsRecognizeDialog?.isShowing == true) { goodsRecognizeDialog?.isShowing == true
goodsRecognizeDialog?.dismiss() ) {
goodsRecognizeDialog?.dismiss()
} }
} }
return return
@@ -313,7 +318,8 @@ abstract class GoodsListActivity : ComponentActivity() {
foodList.forEach { foodList.forEach {
it.name = it.name.split("WP")[0] it.name = it.name.split("WP")[0]
} }
val filterList = foodList.filter { it.score < FoodModule.BAG_RATE && it.name.contains("黑袋子")} val filterList =
foodList.filter { it.score < FoodModule.BAG_RATE && it.name.contains("黑袋子") }
if (filterList.isNotEmpty()) { if (filterList.isNotEmpty()) {
runOnUiThread { runOnUiThread {
toast("当前物品可能被袋子遮挡,请检查后重试") toast("当前物品可能被袋子遮挡,请检查后重试")
@@ -622,14 +628,17 @@ abstract class GoodsListActivity : ComponentActivity() {
} }
} }
fun uploadImage(goodsId:String, goodsName:String, imageFile: File?) { fun uploadImage(goodsId: String, goodsName: String, imageFile: File?) {
if (imageFile == null) { lifecycleScope.launch {
return if (imageFile == null) {
} return@launch
val list = mutableListOf<File>() }
list.add(imageFile) val list = mutableListOf<File>()
viewModel.uploadMultipleImages(goodsId, goodsName, list) { list.add(imageFile)
Timber.tag(TAG).d("uploadMultipleImages: ${it}") val map = hashMapOf<String, RequestBody>()
map["goodsId"] = goodsId.toRequestBody()
map["goodsName"] = goodsName.toRequestBody()
viewModel.uploadMultipleImages(files = list, params = map)
} }
} }
@@ -0,0 +1,95 @@
package com.sw.inbound.dialog;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import com.sw.inbound.R;
/**
* 加载进度条弹窗
*/
public class CustomDialog extends Dialog {
/**
* 宽高由布局文件中指定(但是最底层的宽度无效,可以多嵌套一层解决)
*/
public CustomDialog(Context context, View layout, int style) {
super(context, style);
setContentView(layout);
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
/**
* 宽高由该方法的参数设置
*/
public CustomDialog(Context context, int width, int height, View layout,
int style) {
super(context, style);
// 设置内容
setContentView(layout);
// 设置窗口属性
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
// 设置宽度、高度、密度、对齐方式
float density = getDensity(context);
params.width = (int) (width * density);
params.height = (int) (height * density);
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
/**
* 获取显示密度
*
* @param context
* @return
*/
public float getDensity(Context context) {
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
return dm.density;
}
private void fullScreenImmersive(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_FULLSCREEN;
view.setSystemUiVisibility(uiOptions);
}
}
@Override
public void show() {
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
super.show();
// fullScreenImmersive(getWindow().getDecorView());
// this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}
}
@@ -213,11 +213,11 @@ class RemoteRepository @Inject constructor(
} }
} }
suspend fun uploadMultipleImages(fileList: List<File>, param: Map<String, String>): ApiResponse<String> { suspend fun uploadMultipleImages(fileList: List<File>, params: HashMap<String, RequestBody>): ApiResponse<String> {
val paramsMap = hashMapOf<String, RequestBody>() // val paramsMap = hashMapOf<String, RequestBody>()
param.forEach { (key, value) -> // param.forEach { (key, value) ->
paramsMap[key] = value.toRequestBody("text/plain".toMediaTypeOrNull()) // paramsMap[key] = value.toRequestBody("text/plain".toMediaTypeOrNull())
} // }
// 准备文件参数 // 准备文件参数
val fileParts = mutableListOf<MultipartBody.Part>() val fileParts = mutableListOf<MultipartBody.Part>()
@@ -232,7 +232,7 @@ class RemoteRepository @Inject constructor(
fileParts.add(filePart) fileParts.add(filePart)
} }
return safeApiCall { return safeApiCall {
apiService.uploadMultipleImages(params = paramsMap, goodsPics = fileParts) apiService.uploadMultipleImages(params = params, goodsPics = fileParts)
} }
} }
} }
@@ -0,0 +1,40 @@
package com.sw.inbound.utils
import com.sw.inbound.objbox.FoodCollectionBean
import java.util.concurrent.atomic.AtomicInteger
import kotlin.collections.chunked
import kotlin.collections.count
class ImageUploader(
private val totalList: List<FoodCollectionBean>,
private val uploadImage: suspend (List<FoodCollectionBean>)-> Boolean,
private val onProgress: (Int, List<FoodCollectionBean>) -> Unit,
private val onError:(List<FoodCollectionBean>) -> Unit,
private val onComplete:() -> Unit
) {
companion object {
private const val BATCH_SIZE = 5
}
private val uploadedCount = AtomicInteger(0)
suspend fun processUploads() {
val batches = totalList.chunked(BATCH_SIZE)
for (batch in batches) {
val success = uploadImage(batch)
if (!success) {
//println("上传失败,终止流程")
onError(batch)
return
}
val fileCount = batch.count { it.imageFile!=null }
uploadedCount.addAndGet(fileCount)
onProgress(uploadedCount.get(), batch)
//println("已上传 ${uploadedCount.get()}/$totalImages")
}
onComplete()
//println("流程完成,总计上传 ${uploadedCount.get()} 张图片")
}
}
@@ -9,6 +9,7 @@ import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.repository.RemoteRepository import com.sw.inbound.repository.RemoteRepository
import com.sw.inbound.utils.ext.toJsonString import com.sw.inbound.utils.ext.toJsonString
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import okhttp3.RequestBody
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
@@ -347,7 +348,7 @@ class ReceiptViewModel @Inject constructor(
// } // }
// } // }
fun uploadImage(file:File, callback: (String?) -> Unit) { fun uploadImage(file: File, callback: (String?) -> Unit) {
launchWithLoading { launchWithLoading {
val resp = repository.uploadImage(file) val resp = repository.uploadImage(file)
if (!parseResponse(resp)) { if (!parseResponse(resp)) {
@@ -377,23 +378,42 @@ class ReceiptViewModel @Inject constructor(
callback(true) callback(true)
} }
} }
fun uploadMultipleImages(goodsId:String, goodsName:String, files:List<File?>, callback: (Boolean) -> Unit) { // fun uploadMultipleImages(goodsId:String, goodsName:String, files:List<File?>, callback: (Boolean) -> Unit) {
launchWithLoading { // launchWithLoading {
val map = mutableMapOf<String, String>() // val map = mutableMapOf<String, String>()
map["goodsId"] = goodsId // map["goodsId"] = goodsId
map["goodsName"] = goodsName // map["goodsName"] = goodsName
val fileList = files.filterNotNull() // val fileList = files.filterNotNull()
if (fileList.isEmpty()) { // if (fileList.isEmpty()) {
callback(false) // callback(false)
return@launchWithLoading // return@launchWithLoading
} // }
val resp = repository.uploadMultipleImages(fileList = fileList, param = map) // val resp = repository.uploadMultipleImages(fileList = fileList, param = map)
if (!parseResponse(resp)) { // if (!parseResponse(resp)) {
callback(false) // callback(false)
return@launchWithLoading // return@launchWithLoading
} // }
callback(resp.code == "00000") // callback(resp.code == "00000")
// }
// }
suspend fun uploadMultipleImages(
files: List<File?>,
params: HashMap<String, RequestBody>
): Boolean {
// val map = mutableMapOf<String, String>()
// map["goodsId"] = goodsId
// map["goodsName"] = goodsName
val fileList = files.filterNotNull()
if (fileList.isEmpty()) {
return true
} }
val resp = repository.uploadMultipleImages(fileList = fileList, params = params)
// if (!parseResponse(resp)) {
// callback(false)
// return@launchWithLoading
// }
return resp.code == "00000"
} }
} }
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
<solid android:color="@color/black" />
</shape>
@@ -353,18 +353,18 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="1" /> android:layout_weight="1" />
<TextView <!-- <TextView-->
android:id="@+id/btnUploadImage" <!-- android:id="@+id/btnUploadImage"-->
android:layout_width="270dp" <!-- android:layout_width="270dp"-->
android:layout_height="90dp" <!-- android:layout_height="90dp"-->
android:layout_gravity="center_vertical" <!-- android:layout_gravity="center_vertical"-->
android:layout_marginEnd="20dp" <!-- android:layout_marginEnd="20dp"-->
android:background="@drawable/bg_blue_ripple" <!-- android:background="@drawable/bg_blue_ripple"-->
android:gravity="center" <!-- android:gravity="center"-->
android:text="待上传图片" <!-- android:text="待上传图片"-->
android:textColor="@color/white" <!-- android:textColor="@color/white"-->
android:textSize="26sp" <!-- android:textSize="26sp"-->
android:textStyle="bold" /> <!-- android:textStyle="bold" />-->
<TextView <TextView
android:id="@+id/btnSave" android:id="@+id/btnSave"
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/dialog_waiting"
android:paddingStart="20dp"
android:paddingTop="10dp"
android:paddingEnd="20dp"
android:paddingBottom="10dp">
<ProgressBar
android:layout_width="60dp"
android:layout_height="60dp"
android:indeterminateTint="@color/teal_200"
android:indeterminateTintMode="src_atop" />
<TextView
android:id="@+id/tvTip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请稍等"
android:layout_marginStart="10dp"
android:layout_gravity="center_vertical"
android:textColor="@color/white"
android:textSize="26sp" />
</LinearLayout>
+14
View File
@@ -27,4 +27,18 @@
<item name="android:windowIsFloating">true</item> <item name="android:windowIsFloating">true</item>
<item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item>
</style> </style>
<!--圆角Dialog-->
<style name="MyDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.6</item>
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
</style>
</resources> </resources>