增加物品采集功能,解决测试问题
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
package com.sw.inbound.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.viewModels
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.adapter.FoodCollectionAdapter
|
||||
import com.sw.inbound.adapter.GoodsSearchAdapter
|
||||
import com.sw.inbound.databinding.ActivityFoodCollectionBinding
|
||||
import com.sw.inbound.databinding.LayoutCameraPreviewBinding
|
||||
import com.sw.inbound.databinding.LayoutEmptySearchBinding
|
||||
import com.sw.inbound.dialog.Loading
|
||||
import com.sw.inbound.model.response.SearchGoodsInfo
|
||||
import com.sw.inbound.objbox.Food
|
||||
import com.sw.inbound.objbox.FoodCollectionBean
|
||||
import com.sw.inbound.objbox.FoodModule
|
||||
import com.sw.inbound.objbox.ObjectBox
|
||||
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.addOnActionSearchListener
|
||||
import com.sw.inbound.utils.ext.clickWithDebounce
|
||||
import com.sw.inbound.utils.ext.dp
|
||||
import com.sw.inbound.utils.ext.hideKeyboard
|
||||
import com.sw.inbound.utils.ext.toast
|
||||
import com.sw.inbound.viewmodel.ReceiptViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.objectbox.Box
|
||||
import io.objectbox.kotlin.boxFor
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FoodCollectionActivity : ComponentActivity() {
|
||||
|
||||
private val TAG = "FoodCollectionActivity"
|
||||
private var selectedFoodName: String = ""
|
||||
|
||||
private var box: Box<Food>? = null
|
||||
private val collectList: MutableList<FoodCollectionBean> = mutableListOf(
|
||||
FoodCollectionBean(isShowCamera = true),
|
||||
FoodCollectionBean(isShowCamera = true),
|
||||
FoodCollectionBean(isShowCamera = true),
|
||||
FoodCollectionBean(isShowCamera = true),
|
||||
FoodCollectionBean(isShowCamera = true),
|
||||
FoodCollectionBean(isShowCamera = true)
|
||||
)
|
||||
private lateinit var binding: ActivityFoodCollectionBinding
|
||||
private lateinit var previewView: PreviewView
|
||||
|
||||
val viewModel: ReceiptViewModel by viewModels()
|
||||
val PAGE_SIZE = 30
|
||||
private val cameraUtils: CameraUtils by lazy {
|
||||
CameraUtils(this)
|
||||
}
|
||||
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
|
||||
it.isFinish = false
|
||||
it.isShowCamera = true
|
||||
}
|
||||
collectionAdapter.notifyItemChanged(position)
|
||||
// if (position == collectList.size - 1) {
|
||||
//
|
||||
// return@addOnItemChildClickListener
|
||||
// }
|
||||
// collectList.removeAt(position)
|
||||
// adapter.notifyItemRemoved(position)
|
||||
// adapter.notifyItemRangeChanged(position, collectList.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
cameraUtils.bind()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
cameraUtils.unbind()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityFoodCollectionBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
cameraUtils.initCamera()
|
||||
val previewBinding =
|
||||
LayoutCameraPreviewBinding.inflate(layoutInflater, binding.flCameraPreview)
|
||||
previewView = previewBinding.previewView.also {
|
||||
it.updateLayoutParams {
|
||||
width = 420.dp
|
||||
height = 420.dp
|
||||
}
|
||||
}
|
||||
cameraUtils.setPreviewController(previewView)
|
||||
binding.btnBack.setOnClickListener { finish() }
|
||||
binding.rvFoodCollection.let {
|
||||
it.layoutManager = GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false)
|
||||
it.adapter = collectionAdapter
|
||||
}
|
||||
|
||||
binding.ivGoodsSearch.setOnClickListener { searchGoods() }
|
||||
binding.etGoodsInput.let { v ->
|
||||
v.addOnActionSearchListener {
|
||||
searchGoods()
|
||||
}
|
||||
}
|
||||
|
||||
binding.btnSave.setOnClickListener {
|
||||
if (clickIndex == -1) {
|
||||
Toast.makeText(this, "请选择物品名称", Toast.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
}
|
||||
val count = collectList.count {it.bitmap!=null}
|
||||
if (count == 0) {
|
||||
Toast.makeText(this, "请拍摄物品照片", Toast.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
}
|
||||
vectorThread()
|
||||
}
|
||||
binding.btnTakePhoto.clickWithDebounce {
|
||||
takePhoto()
|
||||
}
|
||||
binding.btnAddDefault.clickWithDebounce {
|
||||
Thread{
|
||||
FoodModule.initDefFoodData(this) {
|
||||
runOnUiThread {
|
||||
toast("添加完成")
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
binding.btnRemoveDefault.clickWithDebounce {
|
||||
if (box == null) {
|
||||
box = ObjectBox.boxStore.boxFor(Food::class)
|
||||
}
|
||||
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)
|
||||
it.adapter = searchAdapter
|
||||
}
|
||||
binding.refreshLayout.let {
|
||||
it.setEnableRefresh(true)
|
||||
it.setEnableLoadMore(false)
|
||||
it.setOnRefreshListener {
|
||||
pageNo = 1
|
||||
searchGoods()
|
||||
}
|
||||
it.setOnLoadMoreListener {
|
||||
searchGoods()
|
||||
}
|
||||
}
|
||||
loadEmptyView()
|
||||
}
|
||||
|
||||
private var pageNo = 1
|
||||
private var clickIndex = -1
|
||||
|
||||
private val searchGoodsList: MutableList<SearchGoodsInfo.Record> = mutableListOf()
|
||||
private val searchAdapter by lazy {
|
||||
GoodsSearchAdapter(searchGoodsList).apply {
|
||||
isStateViewEnable = true
|
||||
setOnItemClickListener { adapter, view, position ->
|
||||
clickIndex = position
|
||||
if (list[position].isSelected) {
|
||||
return@setOnItemClickListener
|
||||
}
|
||||
list.forEach { item ->
|
||||
item.isSelected = false
|
||||
}
|
||||
list[position].isSelected = true
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishRefresh() {
|
||||
binding.refreshLayout.let {
|
||||
if (pageNo == 1) {
|
||||
it.finishRefresh(500)
|
||||
} else {
|
||||
it.finishLoadMore(500)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun takePhoto() {
|
||||
val count = collectList.count { it.bitmap != null }
|
||||
if (count == 6) {
|
||||
toast("每次只允许保存6条数据")
|
||||
return
|
||||
}
|
||||
cameraUtils.takePhoto(cameraCallback)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun clearData() {
|
||||
collectList.forEach {
|
||||
it.bitmap = null
|
||||
it.isShowCamera = true
|
||||
it.isFinish = false
|
||||
}
|
||||
collectionAdapter.notifyDataSetChanged()
|
||||
|
||||
clickIndex = -1
|
||||
binding.etGoodsInput.setText("")
|
||||
searchGoodsList.clear()
|
||||
searchAdapter.notifyDataSetChanged()
|
||||
loadEmptyView()
|
||||
}
|
||||
|
||||
private val cameraCallback:(Uri) -> Unit = { uri->
|
||||
val index = collectList.indexOfFirst { it.bitmap == null }
|
||||
if (index == -1) {
|
||||
toast("每次只允许保存6条数据")
|
||||
rerurn@cameraCallback
|
||||
}
|
||||
ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
|
||||
val cropBitmap = BitmapCropper.cropCenter(
|
||||
original = bitmap,
|
||||
targetWidth = 1000, targetHeight = 1300,
|
||||
offsetX = 30, offsetY = 100
|
||||
)
|
||||
val file = BitmapSaver.saveToAppFilesDir(
|
||||
cropBitmap, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
|
||||
)
|
||||
Timber.d("${this.javaClass.simpleName}-searchFood-裁剪bitmap保存文件路径:${file?.absolutePath}")
|
||||
|
||||
collectList[index].let {
|
||||
it.bitmap = cropBitmap
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
private fun vectorThread() {
|
||||
Loading.show(this)
|
||||
Thread {
|
||||
collectList.filter { it.bitmap != null }
|
||||
.forEachIndexed { index, it ->
|
||||
image2VectorTask(it.bitmap!!, index)
|
||||
}
|
||||
runOnUiThread {
|
||||
window.decorView.postDelayed({
|
||||
Loading.dismiss()
|
||||
toast("保存成功")
|
||||
}, 1000)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun image2VectorTask(bitmap: Bitmap, position: Int) {
|
||||
if (box == null) {
|
||||
box = ObjectBox.boxStore.boxFor(Food::class)
|
||||
}
|
||||
val imageVector = FoodModule.bitmap2FloatArray(bitmap)
|
||||
box?.put(Food(name = searchGoodsList[clickIndex].goodsName, foodIdx = 0, foodVector = imageVector))
|
||||
collectList[position].let {
|
||||
it.imageVector = imageVector
|
||||
it.isFinish = true
|
||||
}
|
||||
runOnUiThread {
|
||||
collectionAdapter.notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun searchGoods() {
|
||||
val searchName = binding.etGoodsInput.text.toString().trim()
|
||||
if (searchName.isBlank()) {
|
||||
toast("请输入物品名称")
|
||||
finishRefresh()
|
||||
return
|
||||
}
|
||||
searchGoods(
|
||||
searchName = searchName,
|
||||
pageNo = pageNo
|
||||
) { records ->
|
||||
finishRefresh()
|
||||
binding.etGoodsInput.hideKeyboard()
|
||||
if (pageNo == 1) {
|
||||
searchGoodsList.clear()
|
||||
}
|
||||
searchGoodsList.addAll(records)
|
||||
if (searchGoodsList.isEmpty()) {
|
||||
loadEmptyView()
|
||||
return@searchGoods
|
||||
}
|
||||
val enableLoadMore = records.size >= PAGE_SIZE
|
||||
binding.refreshLayout.setEnableLoadMore(enableLoadMore)
|
||||
if (enableLoadMore) {
|
||||
pageNo++
|
||||
}
|
||||
binding.rvSearch.layoutManager =
|
||||
GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false)
|
||||
searchAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private var emptyBinding: LayoutEmptySearchBinding? = null
|
||||
private fun loadEmptyView() {
|
||||
binding.rvSearch.layoutManager =
|
||||
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
if (emptyBinding == null) {
|
||||
emptyBinding = LayoutEmptySearchBinding.inflate(layoutInflater, binding.rvSearch, false)
|
||||
}
|
||||
emptyBinding?.root?.let { layout ->
|
||||
layout.setOnClickListener { layout.hideKeyboard() }
|
||||
searchAdapter.stateView = layout
|
||||
}
|
||||
}
|
||||
fun searchGoods(
|
||||
searchName: String,
|
||||
pageNo: Int,
|
||||
pageSize: Int = PAGE_SIZE,
|
||||
callback: (List<SearchGoodsInfo.Record>) -> Unit
|
||||
) {
|
||||
runBlocking {
|
||||
val records = viewModel.searchGoodsInfoList2(
|
||||
goodsName = searchName,
|
||||
pageNo = pageNo,
|
||||
pageSize = pageSize
|
||||
)
|
||||
runOnUiThread {
|
||||
callback(records)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user