结算页面、设置页面

This commit is contained in:
2025-11-19 18:35:53 +08:00
parent 9818dfc438
commit 60b712f216
75 changed files with 2983 additions and 647 deletions
@@ -1,5 +1,6 @@
package com.sw.dualscreen.activity
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.Outline
@@ -28,11 +29,13 @@ import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.R
import com.sw.dualscreen.adapter.GenericItemAdapter
import com.sw.dualscreen.adapter.GridSpacingItemDecoration
import com.sw.dualscreen.adapter.SearchFoodAdapter
import com.sw.dualscreen.adapter.dpToPx
import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.databinding.ItemFoodInfoBinding
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.FoodModule.IdNameScore
@@ -55,6 +58,10 @@ import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale
import java.util.concurrent.Executors
import kotlin.math.roundToInt
@@ -67,7 +74,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private var isAnalyzing = true // 控制是否进行图像分析
private var presentation: SecondaryScreenPresentation? = null
private val executor = Executors.newSingleThreadExecutor()
private lateinit var adapter: GenericItemAdapter<FoodInfo, ItemFoodInfoBinding>
private val searchFoodList = mutableListOf<FoodInfo>()
private val adapter by lazy {
SearchFoodAdapter(searchFoodList).apply {
setOnItemClickListener { adapter, view, position ->
searchFoodList.forEachIndexed { index, info ->
searchFoodList[index].isChecked = index == position
}
val item = searchFoodList[position]
Timber.d("itemClick ${item.foodName}, position = $position")
item.photoUri = null
checkedItem = item
notifyDataSetChanged()
// TODO 暂时注释---------------
//updateCurrentFood(item)
}
}
}
private var checkedItem: FoodInfo? = null
private var imageAnalysis: ImageAnalysis? = null
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
@@ -102,11 +125,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun initView() {
viewModel.activeEngine()
binding.foodDisplayLayout.setOnClickListener {
val intent = Intent(this, FoodCollectionActivity::class.java)
startActivity(intent)
updateDateTime()
binding.ivSetting.setOnClickListener {
startActivity(Intent(this, SettingActivity::class.java))
finish()
}
//binding.foodDisplayLayout.setOnClickListener {
// val intent = Intent(this, FoodCollectionActivity::class.java)
// startActivity(intent)
// finish()
//}
binding.previewView.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(0, 0, view.width, view.height, 12f.dp)
@@ -121,49 +149,57 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
bottomSheetDialog!!.show(supportFragmentManager, "CustomBottomSheetDialog")
}
val spinnerAdapter = ArrayAdapter<String>(
this,
R.layout.item_for_custom_spinner,
arrayOf("即放即取", "余量取餐")
)
binding.spinner.adapter = spinnerAdapter
//val spinnerAdapter = ArrayAdapter<String>(
// this,
// R.layout.item_for_custom_spinner,
// arrayOf("即放即取", "余量取餐")
//)
//binding.spinner.adapter = spinnerAdapter
val mode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0)
binding.spinner.setSelection(mode ?: 0)
//binding.spinner.setSelection(mode ?: 0)
presentation?.updateMealPickupMode(mode ?: 0)
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, position)
updateCurrentFood(null)
isRecognitionFood = true
presentation?.updateMealPickupMode(position)
SensorScaleUtils.zero()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
//binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
// override fun onItemSelected(
// parent: AdapterView<*>?,
// view: View?,
// position: Int,
// id: Long
// ) {
// SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, position)
// updateCurrentFood(null)
// isRecognitionFood = true
// presentation?.updateMealPickupMode(position)
//
// SensorScaleUtils.zero()
// }
//
// override fun onNothingSelected(parent: AdapterView<*>?) {}
//}
//adapter = createAdapter()
binding.recyclerview.let {
it.layoutManager = GridLayoutManager(this, 2)
it.adapter = adapter
}
adapter = createAdapter()
binding.recyclerview.layoutManager = GridLayoutManager(this, 2)
// 添加间距装饰(12dp)
binding.recyclerview.addItemDecoration(
GridSpacingItemDecoration(
spanCount = 2,
spacing = dpToPx(30),
includeEdge = false // 包含边缘间距
)
)
binding.recyclerview.adapter = adapter
//binding.recyclerview.addItemDecoration(
// GridSpacingItemDecoration(
// spanCount = 2,
// spacing = dpToPx(30),
// includeEdge = false // 包含边缘间距
// )
//)
//binding.recyclerview.adapter = adapter
binding.tvFoodName.setOnClickListener {
SensorScaleUtils.zero()
}
binding.tvRescan.setOnClickListener {
debouncer.debounce { recognizeFood() }
}
binding.btnPay.setOnClickListener {
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, checkedItem)
})
}
}
fun updateCurrentFood(foodInfo: FoodInfo?) {
@@ -204,7 +240,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// }
lifecycleScope.launch {
viewModel.identifiedFoodInfoList.collect { list ->
adapter.updateData(list)
//adapter.updateData(list)
searchFoodList.clear()
searchFoodList.addAll(list)
adapter.notifyDataSetChanged()
//TODO 暂时写死数据测试---------------------------
binding.flPay.visible()
binding.recyclerview.visible()
searchFoodList.clear()
searchFoodList.add(FoodInfo(foodName = "岐山臊子面"))
searchFoodList.add(FoodInfo(foodName = "肉末干拌面"))
searchFoodList.add(FoodInfo(foodName = "雪菜肉丝面"))
searchFoodList.add(FoodInfo(foodName = "康帅博方便面"))
searchFoodList.add(FoodInfo(foodName = "担担面"))
searchFoodList.add(FoodInfo(foodName = "四合一干拌面"))
adapter.notifyDataSetChanged()
if (list.isNotEmpty()) {
checkedItem = list[0]
checkedItem!!.photoUri = lastPhotoUri
@@ -213,7 +265,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
}
SensorScaleUtils.startScale { weight ->
SensorScaleUtils.addWeightListener { weight ->
Timber.d("registerDataChange weight = $weight")
presentation?.updateWeight(weight)
@@ -281,6 +334,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
@SuppressLint("NotifyDataSetChanged")
private fun updateFoodInfo(list: List<FoodInfo>, scoreList: List<IdNameScore>) {
Timber.d("registerDataChange识别后查询接口数据:${GsonUtils.toJson(list)}")
list.forEach { foodInfo ->
@@ -288,7 +342,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val score = scoreItem?.score ?: 0.0
foodInfo.score = ((1 - score) * 10000).roundToInt()
}
adapter.updateData(list)
searchFoodList.clear()
searchFoodList.addAll(list)
adapter.notifyDataSetChanged()
//adapter.updateData(list)
if (list.isNotEmpty()) {
checkedItem = list[0]
checkedItem!!.photoUri = lastPhotoUri
@@ -298,33 +355,33 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemFoodInfoBinding> {
return GenericItemAdapter(
items = emptyList(),
bindingInflater = ItemFoodInfoBinding::inflate,
bindCallback = { item, position ->
val score = (item.score / 100.0).format2String(2)
this.tvName.text = "${item.foodName}\n${score}%"
if (item.id != checkedItem?.id) {
this.tvName.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
this.tvName.setTextColor(resources.getColor(R.color.identify_normal))
this.llRoot.setBackgroundResource(R.drawable.grid_item_normal)
} else {
this.tvName.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
this.tvName.setTextColor(resources.getColor(R.color.identify_checked))
this.llRoot.setBackgroundResource(R.drawable.grid_item_checked)
}
//
this.llRoot.setOnClickListener {
Timber.d("itemClick ${item.foodName}, position = $position")
item.photoUri = null
checkedItem = item
adapter.notifyDataSetChanged()
updateCurrentFood(item)
}
}
)
}
// private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemFoodInfoBinding> {
// return GenericItemAdapter(
// items = emptyList(),
// bindingInflater = ItemFoodInfoBinding::inflate,
// bindCallback = { item, position ->
// val score = (item.score / 100.0).format2String(2)
// this.tvName.text = "${item.foodName}\n${score}%"
// if (item.id != checkedItem?.id) {
// this.tvName.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
// this.tvName.setTextColor(resources.getColor(R.color.identify_normal))
// this.llRoot.setBackgroundResource(R.drawable.grid_item_normal)
// } else {
// this.tvName.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
// this.tvName.setTextColor(resources.getColor(R.color.identify_checked))
// this.llRoot.setBackgroundResource(R.drawable.grid_item_checked)
// }
////
// this.llRoot.setOnClickListener {
// Timber.d("itemClick ${item.foodName}, position = $position")
// item.photoUri = null
// checkedItem = item
// adapter.notifyDataSetChanged()
// updateCurrentFood(item)
// }
// }
// )
// }
private fun setupCamera() {
Timber.d("setupCamera")
@@ -496,15 +553,24 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
@SuppressLint("NotifyDataSetChanged")
fun clearFoodList() {
adapter.updateData(listOf())
//adapter.updateData(listOf())
searchFoodList.clear()
adapter.notifyDataSetChanged()
}
override fun onDestroy() {
SensorScaleUtils.closeScale()
//SensorScaleUtils.closeScale()
presentation?.dismiss()
super.onDestroy()
shutdownCamera()
}
private fun updateDateTime() {
val formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA)
val dateTime = formatter.format(LocalDateTime.now(ZoneId.of("Asia/Shanghai")))
binding.tvTitleTime.text = dateTime
}
}