接口调试、增加人脸识别后主副屏支付金额逻辑、其它优化

This commit is contained in:
2025-12-03 18:40:47 +08:00
parent 29188c5944
commit 8899cae323
34 changed files with 1202 additions and 402 deletions
@@ -2,13 +2,12 @@ package com.sw.dualscreen.activity
import android.app.Dialog
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.hardware.display.DisplayManager
import android.os.Bundle
import android.text.TextUtils
import android.view.Display
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
@@ -93,6 +92,19 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
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 contentView = mDialogWaiting?.findViewById<ViewGroup>(android.R.id.content)
val tvTip = contentView?.findViewById<TextView>(R.id.tvTip)
tvTip?.text = tip
}
private var launchPermissionCallback: IActivityResult.RequestPermissionCallback? = null
fun requestSinglePermissionResult(
@@ -10,7 +10,9 @@ import com.sw.dualscreen.databinding.ActivityCollectedFoodBinding
import com.sw.dualscreen.databinding.LayoutEmptySearchBinding
import com.sw.dualscreen.dialog.WarnDialog
import com.sw.dualscreen.ext.addOnActionSearchListener
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.hideKeyboard
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.objbox.CollectedFoodInfo
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.ObjectBox
@@ -21,6 +23,11 @@ import io.objectbox.Box
import io.objectbox.kotlin.boxFor
class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
companion object {
private const val PAGE_SIZE = 100
}
private val viewModel by viewModels<UserViewModel>()
override fun getViewModel(): BaseViewModel {
return viewModel
@@ -33,7 +40,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
private val list: MutableList<CollectedFoodInfo> = mutableListOf()
private val adapter by lazy {
CollectedFoodNewAdapter(list).apply {
isStateViewEnable = true
// isStateViewEnable = true
addOnItemChildClickListener(R.id.ivDeleteFood) { _, _, position ->
deleteGoods(position)
}
@@ -42,6 +49,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
override fun initialize() {
super.initialize()
//binding.root.setOnClickListener { it.hideKeyboard() }
binding.rvFoodList.let {
it.layoutManager = LinearLayoutManager(this)
it.adapter = adapter
@@ -65,14 +73,30 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
ToastUtils.showToast("请输入物品名称")
return@addOnActionSearchListener
}
pageNo = 1
getCollectGoods(searchName)
}
v.addTextChangedListener {
if (it.isNullOrBlank()) {
pageNo = 1
getCollectGoods()
}
}
}
binding.refreshLayout.let {
it.setEnableRefresh(true)
it.setEnableLoadMore(false)
it.setOnRefreshListener {
pageNo = 1
getCollectGoods()
}
it.setOnLoadMoreListener {
getCollectGoods()
}
}
binding.emptyInclude.root.setOnClickListener {
it.hideKeyboard()
}
getCollectGoods()
}
@@ -81,54 +105,81 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
@SuppressLint("NotifyDataSetChanged")
private fun getCollectGoods(searchName: String? = null) {
if (box == null) {
box = ObjectBox.boxStore.boxFor(Food::class)
}
list.clear()
val totalList = box?.all
?.filter { it.name!=null }
?.groupBy { it.name!! }
?.map { CollectedFoodInfo(foodName = it.key, foodCount = it.value.size) }
//var queryMap:Map<String, List<Food>> ?= null
if (searchName.isNullOrBlank().not()) {
//queryMap = totalMap?.filter { it.key.contains(searchName) }
val temp = totalList?.filter { it.foodName?.contains(searchName) == true}
if (temp.isNullOrEmpty().not()) {
list.addAll(temp)
}
} else {
if (totalList.isNullOrEmpty().not()) {
list.addAll(totalList)
}
}
adapter.notifyDataSetChanged()
if (list.isEmpty()) {
loadEmptyView()
}
binding.root.hideKeyboard()
// if (box == null) {
// box = ObjectBox.boxStore.boxFor(Food::class)
// }
// list.clear()
// val totalList = box?.all
// ?.filter { it.name!=null }
// ?.groupBy { it.name!! }
// ?.map { CollectedFoodInfo(foodName = it.key, foodCount = it.value.size) }
// //var queryMap:Map<String, List<Food>> ?= null
// if (searchName.isNullOrBlank().not()) {
// //queryMap = totalMap?.filter { it.key.contains(searchName) }
// val temp = totalList?.filter { it.foodName?.contains(searchName) == true}
// if (temp.isNullOrEmpty().not()) {
// list.addAll(temp)
// }
// } else {
// if (totalList.isNullOrEmpty().not()) {
// list.addAll(totalList)
// }
// }
// adapter.notifyDataSetChanged()
// if (list.isEmpty()) {
// loadEmptyView()
// }
viewModel.getCollectedFoodList(pageNo = pageNo) {
if (it.isNotEmpty()) {
list.addAll(it)
runOnUiThread {
adapter.notifyDataSetChanged()
}
viewModel.getCollectedFoodList(
pageNo = pageNo,
pageSize = PAGE_SIZE,
foodName = searchName ?: ""
) { items ->
runOnUiThread {
loadFoodList(items)
}
}
}
@SuppressLint("NotifyDataSetChanged")
private fun loadFoodList(items: List<CollectedFoodInfo>) {
finishRefresh()
if (pageNo == 1 && items.isEmpty()) {
list.clear()
adapter.notifyDataSetChanged()
loadEmptyView()
binding.refreshLayout.setEnableLoadMore(false)
return
}
binding.refreshLayout.visible()
binding.emptyInclude.root.gone()
if (pageNo == 1) {
list.clear()
}
list.addAll(items)
val isEnableLoadMore = items.size >= PAGE_SIZE
if (isEnableLoadMore) {
pageNo++
}
binding.refreshLayout.setEnableLoadMore(isEnableLoadMore)
adapter.notifyDataSetChanged()
binding.root.hideKeyboard()
}
private var pageNo = 1
private var emptyBinding: LayoutEmptySearchBinding? = null
// private var emptyBinding: LayoutEmptySearchBinding? = null
private fun loadEmptyView() {
if (emptyBinding == null) {
emptyBinding =
LayoutEmptySearchBinding.inflate(layoutInflater, binding.rvFoodList, false)
}
emptyBinding?.root?.let { layout ->
layout.setOnClickListener { layout.hideKeyboard() }
adapter.stateView = layout
}
binding.refreshLayout.gone()
binding.emptyInclude.root.visible()
//if (emptyBinding == null) {
// emptyBinding =
// LayoutEmptySearchBinding.inflate(layoutInflater, binding.rvFoodList, false)
//}
//emptyBinding?.root?.let { layout ->
// layout.setOnClickListener { layout.hideKeyboard() }
// adapter.stateView = layout
//}
}
private fun deleteGoods(position: Int) {
@@ -154,4 +205,16 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
}.start()
}).show()
}
private fun finishRefresh() {
binding.refreshLayout.let {
if (pageNo == 1) {
it.finishRefresh(500)
} else {
it.finishLoadMore(500)
}
}
}
}
@@ -11,6 +11,7 @@ import android.os.Looper
import android.text.TextUtils
import android.view.View
import android.view.ViewOutlineProvider
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
@@ -21,20 +22,22 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.google.common.util.concurrent.ListenableFuture
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.adapter.SearchFoodAdapter
import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.FoodModule.IdNameScore
import com.sw.dualscreen.presentation.MainScreenPresentation
import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.utils.BitmapSaver
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.GlideUtils
import com.sw.dualscreen.utils.GsonUtils
import com.sw.dualscreen.utils.ImageUtil
import com.sw.dualscreen.utils.SPUtil
@@ -65,8 +68,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private val viewModel by viewModels<UserViewModel>()
private var imageCapture: ImageCapture? = null
private var isAnalyzing = true // 控制是否进行图像分析
// private var presentation: SecondaryScreenPresentation? = null
var isAnalyzing = true // 控制是否进行图像分析
// private var presentation: SecondaryScreenPresentation? = null
private var presentation: MainScreenPresentation? = null
private val executor = Executors.newSingleThreadExecutor()
private val handler by lazy { Handler(Looper.getMainLooper()) }
@@ -86,7 +90,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
}
private var checkedItem: FoodInfo? = null
var checkedItem: FoodInfo? = null
private var imageAnalysis: ImageAnalysis? = null
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
private var canIdentify: Boolean = false
@@ -106,6 +110,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun initialize() {
super.initialize()
addBackEventListener()
FoodModule.init(this)
initView()
setupSecondaryDisplay()
@@ -204,45 +209,44 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// binding.tvRescan.setOnClickListener {
// debouncer.debounce { recognizeFood() }
// }
binding.btnPay.setOnClickListener {
if (checkedItem == null) {
ToastUtils.showToast("暂无识别数据,请搜索选择")
return@setOnClickListener
binding.btnPay.let {
it.run {
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
if (mode == 0) visible() else gone()
}
it.setOnClickListener { v ->
if (checkedItem == null) {
ToastUtils.showToast("暂无识别数据,请搜索选择")
return@setOnClickListener
}
createOrder(checkedItem!!)
}
presentation?.dismiss()
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, checkedItem)
})
}
}
fun updateCurrentFood(foodInfo: FoodInfo?) {
if (foodInfo != null) {
presentation?.updateFood(foodInfo)
binding.tvFoodName.text = foodInfo.foodName
binding.previewView.visibility = View.GONE
binding.ivImg.visibility = View.VISIBLE
val imgUrl = foodInfo.imgUrl
if (TextUtils.isEmpty(imgUrl)) {
takePhoto { imgUri ->
GlideUtils.loadRoundCornerImage(this, imgUri, binding.ivImg, 12)
presentation?.updateFood(foodInfo.copy(imgUrl = imgUri.toString()))
}
} else {
if (foodInfo.photoUri != null) {
GlideUtils.loadRoundCornerImage(this, foodInfo.photoUri, binding.ivImg, 12)
} else {
GlideUtils.loadRoundCornerImage(this, foodInfo.imgUrl, binding.ivImg, 12)
}
}
pauseAnalysis()
} else {
if (foodInfo == null) {
binding.tvFoodName.text = "-"
binding.previewView.visibility = View.VISIBLE
binding.ivImg.visibility = View.GONE
resumeAnalysis()
viewModel.cleanIdentifiedFoodInfoList()
return
}
pauseAnalysis()
presentation?.updateFood(foodInfo)
binding.tvFoodName.text = foodInfo.foodName
binding.previewView.visibility = View.GONE
binding.ivImg.visibility = View.VISIBLE
if (foodInfo.foodImg.isNullOrBlank()) {
takePhoto { imgUri ->
binding.ivImg.load(imgUri)
presentation?.updateFood(foodInfo.copy(foodImg = imgUri.toString()))
}
} else {
binding.ivImg.load(foodInfo.photoUri ?: foodInfo.foodImg)
}
//pauseAnalysis()
}
override fun registerDataChange() {
@@ -343,21 +347,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
@SuppressLint("NotifyDataSetChanged")
private fun updateFoodInfo(list: MutableList<FoodInfo>, scoreList: List<IdNameScore>) {
Timber.d("registerDataChange识别后查询接口数据:${GsonUtils.toJson(list)},识别数据:${GsonUtils.toJson(scoreList)}")
// TODO: 临时测试数据,后续删除-------------------
//if (list.isEmpty()) {
// //binding.flPay.visible()
// //binding.recyclerview.visible()
// //list.add(FoodInfo(foodName = "豆角茄子"))
// //list.add(FoodInfo(foodName = "豆芽炒粉条"))
// //list.add(FoodInfo(foodName = "岐山臊子面"))
// //list.add(FoodInfo(foodName = "肉末干拌面"))
// //list.add(FoodInfo(foodName = "雪菜肉丝面"))
// //list.add(FoodInfo(foodName = "康帅博方便面"))
// //list.add(FoodInfo(foodName = "担担面"))
// //list.add(FoodInfo(foodName = "四合一干拌面"))
//}
// TODO: 临时测试数据,后续删除-------------------
Timber.d(
"registerDataChange识别后查询接口数据:${GsonUtils.toJson(list)},识别数据:${
GsonUtils.toJson(
scoreList
)
}"
)
list.forEach { foodInfo ->
val scoreItem = scoreList.firstOrNull { it.name == foodInfo.foodName }
val score = scoreItem?.score ?: 0.0
@@ -476,7 +472,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
fun resumeAnalysis() {
Timber.d("resumeAnalysis isAnalyzing = $isAnalyzing")
if (isAnalyzing) return
isAnalyzing = true
// isAnalyzing = true
imageAnalysis?.setAnalyzer(executor) { imageProxy ->
if (presentation?.currentStep == 1) {
val bitmap = imageProxy.toBitmap()
@@ -578,13 +574,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
}
//SecondaryScreenPresentation(
// activity = this,
// this,
// display = secondaryDisplay,
// viewModel = viewModel,
// recognizeViewModel = viewModels<RecognizeViewModel>().value
//)
//SecondaryScreenPresentation(
// activity = this,
// this,
// display = secondaryDisplay,
// viewModel = viewModel,
// recognizeViewModel = viewModels<RecognizeViewModel>().value
//)
// presentation!!.setStepChangeCallback { step ->
// if (step == 1) {
// Timber.d("setStepChangeCallback${step}")
@@ -629,6 +625,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val mode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0)
presentation?.updateMealPickupMode(mode ?: 0)
}
override fun onPause() {
super.onPause()
// 取消定时器
@@ -658,4 +655,61 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
handler.postDelayed(timeoutRunnable, TIME_OUT)
lastTouchTime = System.currentTimeMillis()
}
private fun createOrder(foodInfo: FoodInfo) {
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
val realWeight = (lastWeight * 1000).roundToInt()
val order = FoodOrder(
deviceId = GlobalData.deviceId,
foodId = foodInfo.foodId,
foodName = foodInfo.foodName ?: "",
foodMaterialId = foodInfo.foodMaterialId ?: "",
specId = foodInfo.specId ?: "",
foodWeight = realWeight,
eatWeight = realWeight,
//根据specId对应规格重量计算
eatNum = getEatNum(realWeight, foodInfo.specWeight ?: 0.0),
userId = null,
notPay = mode != 0,
)
viewModel.createOrder(order) { orderId ->
runOnUiThread {
if (orderId.isBlank()) {
ToastUtils.showToast("订单id为空")
return@runOnUiThread
}
foodOrderId = orderId
presentation?.dismiss()
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, foodInfo)
putExtra(PayActivity.FOOD_ORDER_ID, orderId)
})
// ToastUtils.showToast("订单已生成")
}
}
}
private fun getEatNum(realWeight: Int, specWeight: Double): Int {
if (realWeight == 0 || specWeight == 0.0) return 0
return (realWeight / specWeight).roundToInt()
}
private var foodOrderId: String = ""
private var isExist = false
fun addBackEventListener() {
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (isExist.not()) {
ToastUtils.showToast("再按一次退出")
isExist = true
binding.root.postDelayed({
isExist = false
}, 2000)
return
}
finish()
}
})
}
}
@@ -1,6 +1,5 @@
package com.sw.dualscreen.activity
import android.view.View
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import com.sw.dualscreen.R
@@ -11,7 +10,7 @@ import com.sw.dualscreen.activity.fragment.pay.PayResultFragment
import com.sw.dualscreen.activity.fragment.pay.ScanQrCodePayFragment
import com.sw.dualscreen.databinding.ActivityPayBinding
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.presentation.pay.FacePayPresentation
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.presentation.pay.ScanQrCodePayPresentation
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
@@ -22,6 +21,10 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
companion object {
const val FOOD_INFO = "foodInfo"
const val TOTAL_AMOUNT = "totalAmount"
const val FOOD_ORDER_ID = "foodOrderId"
// const val MEMBER_INFO = "memberInfo"
const val TAG_PAY_QR_CODE = "tagPayQrCode"
const val TAG_PAY_CASH = "tagPayCash"
const val TAG_PAY_NUMBER = "tagPayNumber"
@@ -42,16 +45,22 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
var foodInfo: FoodInfo? = null
// var totalAmount:Double = 0.0
private var qrCodePayFragment: ScanQrCodePayFragment? = null
private var cashPayFragment: CashPayFragment? = null
private var numberPayFragment: NumberPayFragment? = null
var facePayFragment: FacePayFragment? = null
private var payResultFragment: PayResultFragment? = null
var foodOrderId:String = ""
@Suppress("DEPRECATION")
override fun initialize() {
super.initialize()
foodInfo = intent.getParcelableExtra(FOOD_INFO)
foodOrderId = intent.getStringExtra(FOOD_ORDER_ID)?:""
// totalAmount = intent.getDoubleExtra(TOTAL_AMOUNT,0.0)
// memberInfo = intent.getParcelableExtra(MEMBER_INFO)
binding.tvFoodName.text = foodInfo?.foodName
binding.include.ivPageBack.setOnClickListener { finish() }
binding.include.tvPageTitle.text = "下单结算"
@@ -140,10 +149,10 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
// }
// }
fun showPayResult() {
payResultFragment = PayResultFragment()
showFragment(payResultFragment!!, TAG_PAY_RESULT)
}
// fun showPayResult() {
// payResultFragment = PayResultFragment.instance(1, memberInfo)
// showFragment(payResultFragment!!, TAG_PAY_RESULT)
// }
override fun onDestroy() {
qrCodePayFragment?.presentation?.dismiss()
@@ -154,8 +163,29 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
}
private var scanQrCodePayPresentation: ScanQrCodePayPresentation? = null
fun paySuccess() {
showFragment(PayResultFragment(), "")
var memberInfo: MemberInfo? = null
fun showPayInfo(memberInfo: MemberInfo) {
this.memberInfo = memberInfo
payResultFragment = PayResultFragment.instance(1, memberInfo)
showFragment(payResultFragment!!, TAG_PAY_RESULT)
if (displays.size > 1) {
scanQrCodePayPresentation = ScanQrCodePayPresentation(
activity = this,
display = displays[1],
type = 1
) {
scanQrCodePayPresentation?.dismiss()
}.also {
it.foodName = foodInfo?.foodName
it.totalPrice = foodInfo?.vipPrice?:0.0
}
scanQrCodePayPresentation?.show()
}
}
fun showPaySuccess() {
payResultFragment = PayResultFragment.instance(2, memberInfo!!)
showFragment(payResultFragment!!, TAG_PAY_RESULT)
if (displays.size > 1) {
scanQrCodePayPresentation = ScanQrCodePayPresentation(
activity = this,
@@ -164,8 +194,8 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
) {
scanQrCodePayPresentation?.dismiss()
}.also {
// it.foodName = foodName
// it.payAmount = payAmount
it.foodName = foodInfo?.foodName
it.totalPrice = foodInfo?.vipPrice?:0.0
}
scanQrCodePayPresentation?.show()
}
@@ -17,18 +17,18 @@ class BusinessFragment: BaseFragment<FragmentBusinessBinding>() {
override fun initialize() {
binding.rgCharge.let {
it.setOnCheckedChangeListener { group, checkedId ->
val mode = if (checkedId == R.id.rbChargeYes) 0 else 1
SPUtil.getInstance().put(GlobalKey.KEY_CHARGE_MODE, mode)
}
// it.setOnCheckedChangeListener { group, checkedId ->
// val mode = if (checkedId == R.id.rbChargeYes) 0 else 1
// SPUtil.getInstance().put(GlobalKey.KEY_CHARGE_MODE, mode)
// }
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
it.check(if (mode == 0) R.id.rbChargeYes else R.id.rbChargeNot)
}
binding.rgTakeFood.let {
it.setOnCheckedChangeListener { group, checkedId ->
val mode = if (checkedId == R.id.rbPickAndPlace) 0 else 1
SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, mode)
}
// it.setOnCheckedChangeListener { group, checkedId ->
// val mode = if (checkedId == R.id.rbPickAndPlace) 0 else 1
// SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, mode)
// }
val mode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0)
it.check(if (mode == 0) R.id.rbPickAndPlace else R.id.rbSurplusCalculate)
}
@@ -49,6 +49,8 @@ class BusinessFragment: BaseFragment<FragmentBusinessBinding>() {
mode = if (binding.rgTakeFood.checkedRadioButtonId == R.id.rbPickAndPlace) 0 else 1
SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, mode)
ToastUtils.showToast("设置已保存")
}
SensorScaleUtils.addWeightListener { value ->
val realWeight = (value * 1000).roundToInt()
@@ -12,6 +12,7 @@ import android.widget.Toast
import androidx.camera.view.PreviewView
import androidx.core.net.toUri
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.CollectedFoodActivity
@@ -30,10 +31,12 @@ import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.utils.BitmapSaver
import com.sw.dualscreen.utils.CameraUtils
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.ImageUploader
import com.sw.dualscreen.utils.ImageUtil
import com.sw.plate.utils.ToastUtils
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.launch
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import timber.log.Timber
@@ -44,7 +47,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
companion object {
private const val TAG = "CollectFragment"
const val MAX_COUNT = 5
const val MAX_COUNT = 100
}
private var selectedFoodId: String? = ""
private var selectedFoodName: String? = ""
@@ -181,9 +184,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
Toast.makeText(requireActivity(), "请拍摄菜品照片", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
vectorThread(){
upload()
}
upload()
}
binding.editFoodName.setOnEditorActionListener { v, actionId, event ->
@@ -216,42 +217,71 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
}
}
private fun uploadCollectFoodPics(files: List<File?>, params: HashMap<String, RequestBody>, callback: (Boolean) -> Unit) {
(requireActivity() as SettingActivity).viewModel.uploadCollectFoodPics(files,params, callback)
}
private fun upload() {
val params = HashMap<String, RequestBody>()
//params["placeId"] = restId.toRequestBody()
params["foodId"] = checkedItem!!.foodId.toRequestBody()
params["foodName"] = checkedItem!!.foodName!!.toRequestBody()
//params["foodVector"] = foodVector.toRequestBody()
for (index in foodCollectionList.indices step 5) {
val end = if(index + 5 < foodCollectionList.size - 1) index + 5 else foodCollectionList.size - 1
val subList = foodCollectionList.subList(index, end)
val subFiles = subList.map { it.imageFile }
uploadCollectFoodPics(subFiles, params) { isSuccess->
Timber.tag(TAG).d("uploadMultipleImages: ${isSuccess}")
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()
// }
// }
}
lifecycleScope.launch {
val totalFileCount = foodCollectionList.count { it.imageFile != null }
settingActivity?.showWaitingDialog("图片上传中0/$totalFileCount")
val params = HashMap<String, RequestBody>()
//params["placeId"] = restId.toRequestBody()
params["foodId"] = checkedItem!!.foodId.toRequestBody()
params["foodName"] = checkedItem!!.foodName!!.toRequestBody()
//params["foodVector"] = foodVector.toRequestBody()
ImageUploader(
totalList = foodCollectionList,
uploadImage = { batch->
val files = batch.map { it.imageFile }
(requireActivity() as SettingActivity).viewModel.uploadCollectFoodPics(files,params)
},
onProgress = { count, batch ->
activity?.runOnUiThread {
settingActivity?.showWaitingDialog2("图片上传中$count/$totalFileCount")
batch.forEach {
it.uploadSuccess = true
}
}
},
onError = {
activity?.runOnUiThread {
ToastUtils.showToast("上传失败,请稍后重试")
}
},
onComplete = {
vectorThread()
}
).processUploads()
}
// for (index in foodCollectionList.indices step 5) {
// val end = if(index + 5 < foodCollectionList.size - 1) index + 5 else foodCollectionList.size - 1
// val subList = foodCollectionList.subList(index, end)
// val subFiles = subList.map { it.imageFile }
// uploadCollectFoodPics(subFiles, params) { isSuccess->
// Timber.tag(TAG).d("uploadMultipleImages: ${isSuccess}")
// 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()
//// }
//// }
// }
// }
}
private fun vectorThread(block:()-> Unit) {
private fun vectorThread() {
settingActivity?.showWaitingDialog("加载中……")
Thread {
foodCollectionList
// .filter { it.bitmap != null }
.filter { it.imageVector != null }
// .filter { it.imageVector != null }
.forEachIndexed { index, it ->
if (it.imageVector == null) {
return@forEachIndexed
}
image2VectorTask(imageVector = it.imageVector!!, index)
}
activity?.runOnUiThread {
@@ -18,9 +18,9 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
override fun initialize() {
payActivity = activity as PayActivity
binding.tvFaceState.setOnClickListener {
payActivity?.showPayResult()
}
// binding.tvFaceState.setOnClickListener {
// payActivity?.showPayResult()
// }
foodName = payActivity?.foodInfo?.foodName
payAmount = "36.80"
showSubScreen()
@@ -1,16 +1,47 @@
package com.sw.dualscreen.activity.fragment.pay
import android.os.Bundle
import android.text.Spanned
import android.text.SpannedString
import android.text.style.AbsoluteSizeSpan
import android.text.style.ForegroundColorSpan
import androidx.core.graphics.toColorInt
import androidx.core.text.buildSpannedString
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.activity.fragment.BaseFragment
import com.sw.dualscreen.databinding.FragmentPayResultBinding
import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.invisible
import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.TextBean
import com.sw.dualscreen.utils.SpannedUtils
class PayResultFragment: BaseFragment<FragmentPayResultBinding>() {
class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
//type = 0,扫码支付默认显示二维码
//type = 1,会员结算显示二维码,是会员则显示名字、头像、手机号、可用余额
//type = 2,支付成功,是会员则显示名字、头像、手机号、可用余额
companion object {
const val PAGE_TYPE = "pageType"
const val MEMBER_INFO = "memberInfo"
fun instance(pageType: Int, memberInfo: MemberInfo): PayResultFragment {
return PayResultFragment().apply {
arguments = Bundle().also {
it.putInt(PAGE_TYPE, pageType)
it.putParcelable(MEMBER_INFO, memberInfo)
}
}
}
}
private var pageType: Int = 1
private var memberInfo: MemberInfo? = null
override fun inflateViewBinding(): FragmentPayResultBinding {
return FragmentPayResultBinding.inflate(layoutInflater)
@@ -22,19 +53,121 @@ class PayResultFragment: BaseFragment<FragmentPayResultBinding>() {
binding.btnBack.setOnClickListener {
//payActivity?.showFacePay()
}
arguments?.let {
pageType = it.getInt(PAGE_TYPE, 0)
memberInfo = it.getParcelable(MEMBER_INFO)
}
binding.ivHeadPic.load(R.mipmap.ic_launcher)
binding.tvUserName.text = "张三"
binding.tvUserPhone.text = "132****5678"
binding.tvUserBalance.text = getBalanceText("0.00")
binding.tvPayAmount.text = "收款金额 20.00 元"
binding.tvPayInfo.text = "应收 38.00 元,余额扣除 16.80 元"
}
totalPrice = payActivity?.foodInfo?.vipPrice ?: 0.0
balance = (memberInfo?.topUpBalance ?: 0.0) + (memberInfo?.rewardBalance ?: 0.0)
realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance
expensesBalance = if (balance >= totalPrice) totalPrice else balance
memberInfo?.let { loadUserInfo(it) }
private fun getBalanceText(amount: String): SpannedString {
return buildSpannedString {
append("¥", AbsoluteSizeSpan(20, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
append(amount, AbsoluteSizeSpan(32, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
when (pageType) {
0 -> {
}
1 -> {
binding.layoutPayInfo.visible()
binding.layoutPaySuccess.gone()
binding.tvRealAmount.text = SpannedUtils.getAmountText(
listOf(
TextBean(text = "¥", textSize = 36),
TextBean(text = realPayPrice.format2String(2), textSize = 60),
)
)
//余额扣除 -36.80 元,扣除后可用余额 10.00 元
//余额扣除 -16.80 元,还需支付 20.00 元
binding.tvUserBalance.text = SpannedUtils.getAmountText(
listOf(
TextBean(text = "¥", textSize = 24),
TextBean(text = balance.format2String(2), textSize = 36),
)
)
binding.tvAccountInfo.text = SpannedUtils.getAmountText(
getAmountList()
)
if (balance >= totalPrice) {
binding.ivPayQrCode.invisible()
binding.btnConfirmPay.isEnabled = true
} else {
binding.ivPayQrCode.visible()
// binding.ivPayQrCode.load(payQrCodePic)
binding.btnConfirmPay.isEnabled = false
}
//点击支付接口成功打开成功页面,或者扫码手动成功回调打开成功页面
binding.btnConfirmPay.setOnClickListener {
payActivity?.showWaitingDialog("支付中,请稍后……")
binding.root.postDelayed({
payActivity?.hideWaitingDialog()
payActivity?.showPaySuccess()
},1000)
}
}
2 -> {
binding.layoutPayInfo.gone()
binding.layoutPaySuccess.visible()
binding.tvPayInfo.text =
"应收 ${totalPrice.format2String(2)} 元,余额扣除 ${expensesBalance.format2String(2)}"
binding.tvPayAmount.text = "收款金额 ${realPayPrice.format2String(2)}"
}
else -> {}
}
}
//总价格
private var totalPrice = 0.0
//余额
private var balance = 0.0
//实际支付金额
private var realPayPrice = 0.0
//扣除余额
private var expensesBalance = 0.0
private fun getAmountList(): List<TextBean> {
val list: MutableList<TextBean> = mutableListOf()
list.add(TextBean(text = "余额扣除 ", textSize = 30, textColor = "#FF889AC2"))
list.add(TextBean(text = "-${expensesBalance.format2String(2)}", textSize = 30, textColor = "#FF0A1428"))
if (balance >= totalPrice) {
//余额大于等于总价格,使用余额支付
TextBean(text = " 元,扣除后可用余额 ", textSize = 30, textColor = "#FF889AC2")
val remainingBalance = balance - totalPrice
TextBean(text = remainingBalance.format2String(2), textSize = 30, textColor = "#FF0A1428")
} else {
//余额小于总价格,使用余额+扫码支付
//实际支付金额
TextBean(text = " 元,还需支付 ", textSize = 30, textColor = "#FF889AC2")
TextBean(text = realPayPrice.format2String(2), textSize = 30, textColor = "#FF0A1428")
TextBean(text = "", textSize = 30, textColor = "#FF889AC2")
}
return list
}
private fun loadUserInfo(item: MemberInfo) {
binding.ivHeadPic.load(R.mipmap.ic_launcher)
binding.tvUserName.text = item.name
val phone = item.phone ?: ""
binding.tvUserPhone.text =
if (phone.length == 11)
phone.replace(phone.substring(3, 7), "****")
else
phone
}
}
@@ -13,6 +13,7 @@ import com.sw.dualscreen.presentation.pay.ScanQrCodePayPresentation
import com.sw.dualscreen.utils.countDownByFlow
import kotlinx.coroutines.Job
import com.sw.dualscreen.databinding.FragmentScanQrcodePayBinding
import com.sw.dualscreen.ext.format2String
class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
@@ -35,7 +36,7 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
payActivity = requireActivity() as PayActivity
foodName = payActivity.foodInfo?.foodName
payAmount = "36.80"
payAmount = payActivity.foodInfo?.specPrice.format2String(2)
payQrCodePic = R.drawable.ic_qrcode
binding.tvRealAmount.text = getAmountText(payAmount?:"")
binding.ivPayQrCode.load(payQrCodePic)
@@ -75,7 +76,7 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
presentation?.dismiss()
}.also {
it.foodName = foodName
it.payAmount = payAmount
it.totalPrice = payActivity.foodInfo?.specPrice?:0.0
it.payQrCodePic = payQrCodePic
}
presentation?.show()