人脸识别支付流程

This commit is contained in:
2025-11-28 09:13:29 +08:00
parent 88179e27b7
commit 9bcd7c9983
20 changed files with 561 additions and 216 deletions
@@ -4,8 +4,10 @@ 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.WindowManager
import android.widget.TextView
@@ -23,6 +25,12 @@ import timber.log.Timber
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
val displays: Array<Display> by lazy {
val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
displayManager.displays
}
protected lateinit var binding: VB
protected lateinit var context: Context
private var mDialogWaiting: CustomDialog? = null
@@ -8,9 +8,11 @@ import com.sw.dualscreen.activity.fragment.pay.CashPayFragment
import com.sw.dualscreen.activity.fragment.pay.FacePayFragment
import com.sw.dualscreen.activity.fragment.pay.NumberPayFragment
import com.sw.dualscreen.activity.fragment.pay.PayResultFragment
import com.sw.dualscreen.activity.fragment.pay.QrCodePayFragment
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.presentation.pay.ScanQrCodePayPresentation
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
@@ -40,10 +42,10 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
var foodInfo: FoodInfo? = null
private var qrCodePayFragment: QrCodePayFragment? = null
private var qrCodePayFragment: ScanQrCodePayFragment? = null
private var cashPayFragment: CashPayFragment? = null
private var numberPayFragment: NumberPayFragment? = null
private var facePayFragment: FacePayFragment? = null
var facePayFragment: FacePayFragment? = null
private var payResultFragment: PayResultFragment? = null
@Suppress("DEPRECATION")
@@ -53,33 +55,48 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
binding.tvFoodName.text = foodInfo?.foodName
binding.include.ivPageBack.setOnClickListener { finish() }
binding.include.tvPageTitle.text = "下单结算"
val payQrCodeClickListener = View.OnClickListener {
if (qrCodePayFragment == null) {
qrCodePayFragment = QrCodePayFragment()
binding.btnPayQrCode.setOnClickListener {
if (binding.btnPayQrCode.isChecked) {
return@setOnClickListener
}
addFragment(qrCodePayFragment!!, TAG_PAY_QR_CODE)
switchButton(true, false, false, false)
showScanQrCodePay()
}
binding.btnPayQrCode.setOnClickListener(payQrCodeClickListener)
binding.btnPayCash.setOnClickListener {
if (binding.btnPayCash.isChecked) {
return@setOnClickListener
}
if (cashPayFragment == null) {
cashPayFragment = CashPayFragment()
}
addFragment(cashPayFragment!!, TAG_PAY_CASH)
showFragment(cashPayFragment!!, TAG_PAY_CASH)
switchButton(false, true, false, false)
}
binding.btnPayNumber.setOnClickListener {
if (binding.btnPayNumber.isChecked) {
return@setOnClickListener
}
if (numberPayFragment == null) {
numberPayFragment = NumberPayFragment()
}
addFragment(numberPayFragment!!, TAG_PAY_NUMBER)
showFragment(numberPayFragment!!, TAG_PAY_NUMBER)
switchButton(false, false, true, false)
}
binding.btnPayFace.setOnClickListener {
if (binding.btnPayFace.isChecked) {
return@setOnClickListener
}
showFacePay()
}
payQrCodeClickListener.onClick(binding.btnPayQrCode)
showScanQrCodePay()
}
private fun showScanQrCodePay() {
if (qrCodePayFragment == null) {
qrCodePayFragment = ScanQrCodePayFragment()
}
showFragment(qrCodePayFragment!!, TAG_PAY_QR_CODE)
switchButton(true, false, false, false)
}
private fun switchButton(vararg arr: Boolean) {
@@ -93,38 +110,49 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
if (facePayFragment == null) {
facePayFragment = FacePayFragment()
}
addFragment(facePayFragment!!, TAG_PAY_FACE)
showFragment(facePayFragment!!, TAG_PAY_FACE)
switchButton(false, false, false, true)
}
private fun addFragment(currentFragment: Fragment, tag: String) {
private fun showFragment(fragment: Fragment, tag: String) {
runCatching {
supportFragmentManager.beginTransaction().apply {
val existFragment = supportFragmentManager.findFragmentByTag(tag)
if (existFragment == null) {
add(R.id.fragmentContainerView, currentFragment, tag)
}
val fragments = supportFragmentManager.fragments
fragments.forEach {
it?.let { fragment ->
if (fragment != currentFragment) {
hide(fragment)
}
}
}
show(currentFragment)
commitAllowingStateLoss()
replace(R.id.fragmentContainerView, fragment)
commitNowAllowingStateLoss()
}
}.onFailure {
it.printStackTrace()
}
}
// private fun showFragment(currentFragment: Fragment, tag: String) {
// runCatching {
// supportFragmentManager.beginTransaction().apply {
// val existFragment = supportFragmentManager.findFragmentByTag(tag)
// if (existFragment == null) {
// add(R.id.fragmentContainerView, currentFragment, tag)
// }
// val fragments = supportFragmentManager.fragments
// fragments.forEach {
// it?.let { fragment ->
// if (fragment != currentFragment) {
// hide(fragment)
// }
// }
// }
// show(currentFragment)
// commitAllowingStateLoss()
// }
// }.onFailure {
// it.printStackTrace()
// }
// }
fun showPayResult() {
if (payResultFragment == null) {
payResultFragment = PayResultFragment()
}
addFragment(payResultFragment!!, TAG_PAY_RESULT)
showFragment(payResultFragment!!, TAG_PAY_RESULT)
}
override fun onDestroy() {
@@ -134,5 +162,22 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
facePayFragment?.presentation?.dismiss()
super.onDestroy()
}
private var scanQrCodePayPresentation: ScanQrCodePayPresentation?=null
fun paySuccess() {
showFragment(PayResultFragment(),"")
if (displays.size > 1) {
scanQrCodePayPresentation = ScanQrCodePayPresentation(
activity = this,
display = displays[1],
type = 2
) {
scanQrCodePayPresentation?.dismiss()
}.also {
// it.foodName = foodName
// it.payAmount = payAmount
}
scanQrCodePayPresentation?.show()
}
}
}
@@ -1,9 +1,9 @@
package com.sw.dualscreen.activity.fragment.pay
import android.graphics.Bitmap
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.activity.fragment.BaseFragment
import com.sw.dualscreen.databinding.FragmentFacePayBinding
import com.sw.dualscreen.presentation.pay.CashPayPresentation
import com.sw.dualscreen.presentation.pay.FacePayPresentation
class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
@@ -37,6 +37,10 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
showSubScreen()
}
fun loadBitmap(frame: Bitmap) {
binding.ivFaceImage.setImageBitmap(frame)
}
private fun showSubScreen() {
// 查找副屏(通常索引为1
if (displays.size > 1) {
@@ -45,6 +49,7 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
display = displays[1],
userViewModel = payActivity!!.userViewModel,
recognizeViewModel = payActivity!!.recognizeViewModel,
// parentTextureView = binding.parentTextureView,
) {
presentation?.dismiss()
}.also {
@@ -1,8 +1,14 @@
package com.sw.dualscreen.activity.fragment.pay
import android.text.Spanned
import android.text.SpannedString
import android.text.style.AbsoluteSizeSpan
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.load
class PayResultFragment: BaseFragment<FragmentPayResultBinding>() {
@@ -10,20 +16,25 @@ class PayResultFragment: BaseFragment<FragmentPayResultBinding>() {
return FragmentPayResultBinding.inflate(layoutInflater)
}
private var payActivity: PayActivity? = null
override fun initialize() {
payActivity = activity as PayActivity
binding.btnBack.setOnClickListener {
payActivity?.showFacePay()
//payActivity?.showFacePay()
}
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 元"
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
//显示时重新查询接口
if (hidden.not()) {
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)
}
}
}
@@ -8,22 +8,25 @@ import androidx.lifecycle.lifecycleScope
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.activity.fragment.BaseFragment
import com.sw.dualscreen.databinding.FragmentQrcodePayBinding
import com.sw.dualscreen.ext.load
import com.sw.dualscreen.presentation.pay.QrCodePayPresentation
import com.sw.dualscreen.presentation.pay.ScanQrCodePayPresentation
import com.sw.dualscreen.utils.countDownByFlow
import kotlinx.coroutines.Job
import com.sw.dualscreen.databinding.FragmentScanQrcodePayBinding
class QrCodePayFragment: BaseFragment<FragmentQrcodePayBinding>() {
class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
companion object {
}
private lateinit var payActivity: PayActivity
private var foodName: String? = null
private var payAmount: String? = null
private var payQrCodePic: Any? = null
var presentation: QrCodePayPresentation?=null
override fun inflateViewBinding(): FragmentQrcodePayBinding {
return FragmentQrcodePayBinding.inflate(layoutInflater)
var presentation: ScanQrCodePayPresentation?=null
override fun inflateViewBinding(): FragmentScanQrcodePayBinding {
return FragmentScanQrcodePayBinding.inflate(layoutInflater)
}
override fun initialize() {
@@ -55,7 +58,7 @@ class QrCodePayFragment: BaseFragment<FragmentQrcodePayBinding>() {
private fun showSubScreen() {
// 查找副屏(通常索引为1
if (displays.size > 1) {
presentation = QrCodePayPresentation(activity = payActivity, display = displays[1]) {
presentation = ScanQrCodePayPresentation(activity = payActivity, type = 0, display = displays[1]) {
presentation?.dismiss()
}.also {
it.foodName = foodName
@@ -83,7 +86,7 @@ class QrCodePayFragment: BaseFragment<FragmentQrcodePayBinding>() {
binding.tvPayResult.text = "待支付(${seconds}s)..."
},
onFinish = {
binding.tvPayResult.text = "支付倒计时结束"
binding.tvPayResult.text = "支付"
}
)
}