28 changed files with 446 additions and 89 deletions
Generated
+1
View File
@@ -0,0 +1 @@
DualScreen
+2 -2
View File
@@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-02-06T02:13:05.230327500Z">
<DropdownSelection timestamp="2026-03-10T03:02:12.156794100Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="Default" identifier="serial=192.168.1.170:5555;connection=1ec19d1e" />
<DeviceId pluginId="Default" identifier="serial=192.168.1.211:5555;connection=7435869e" />
</handle>
</Target>
</DropdownSelection>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="UsePropertyAccessSyntax" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
</profile>
</component>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="userId" value="29face46:19ce5e8d9d0:-7fe0" />
</MTProjectMetadataState>
</option>
</component>
</project>
+4
View File
@@ -0,0 +1,4 @@
kotlin version: 2.0.21
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
1. Kotlin compile daemon is ready
+21
View File
@@ -0,0 +1,21 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.sw.dualscreen",
"variantName": "debug",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "档口双屏_1.0-debug.apk"
}
],
"elementType": "File",
"minSdkVersionForDexing": 29
}
Binary file not shown.
+77
View File
@@ -0,0 +1,77 @@
{
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "1:594331511073099531",
"lastPropertyId": "11:7949771231314213889",
"name": "Food",
"properties": [
{
"id": "1:2317727855243736226",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "4:1528837175750321569",
"name": "foodVector",
"indexId": "1:6010838397086628487",
"type": 28,
"flags": 8
},
{
"id": "5:5561277398349179032",
"name": "collectId",
"type": 9
},
{
"id": "6:8313847979709019172",
"name": "foodId",
"type": 9
},
{
"id": "7:1375536603452792462",
"name": "foodName",
"type": 9
},
{
"id": "8:7942065542192169896",
"name": "version",
"type": 9
},
{
"id": "9:4394472487596452023",
"name": "otherField",
"type": 9
},
{
"id": "10:5704890122356491756",
"name": "createTime",
"type": 9
},
{
"id": "11:7949771231314213889",
"name": "isDel",
"type": 5
}
],
"relations": []
}
],
"lastEntityId": "1:594331511073099531",
"lastIndexId": "1:6010838397086628487",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
"retiredEntityUids": [],
"retiredIndexUids": [],
"retiredPropertyUids": [
340951913928211738,
5484846939472684412
],
"retiredRelationUids": [],
"version": 1
}
+37
View File
@@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.sw.dualscreen",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "档口双屏_1.0-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/档口双屏_1.0-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/档口双屏_1.0-release.dm"
]
}
],
"minSdkVersionForDexing": 29
}
@@ -48,6 +48,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
override fun initialize() {
super.initialize()
registerKeyEvent()
binding.root.setOnClickListener { it.hideKeyboard() }
binding.rvFoodList.let {
it.layoutManager = LinearLayoutManager(this)
@@ -1,8 +1,12 @@
package com.sw.dualscreen.activity
import android.Manifest
import android.content.Intent
import android.os.CountDownTimer
import android.provider.Settings
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.databinding.ActivityInitBinding
@@ -27,6 +31,27 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
private val userViewModel by viewModels<UserViewModel>()
private var pageNum = 1
// 相机权限请求回调
private val requestCameraPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// 权限请求成功,打开 MainActivity
goMainActivity()
} else {
// 权限请求失败,显示弹窗
showPermissionDeniedDialog()
}
}
// 设置页面返回的回调
private val startSettingsLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
// 从设置页面返回,重新检查权限
checkCameraPermissionAfterSettings()
}
override fun getViewModel(): BaseViewModel {
return userViewModel
}
@@ -85,6 +110,7 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
override fun initialize() {
super.initialize()
registerKeyEvent()
initNetworkTimer()
binding.okButton.clickWithDebounce(500) {
checkNetworkTimer?.cancel()
@@ -127,7 +153,7 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
runOnUiThread {
hideWaitingDialog()
binding.root.postDelayed({
goMainActivity()
checkCameraPermissionAndGo()
}, 1000)
}
}
@@ -141,6 +167,53 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
finish()
}
// 检查相机权限
private fun checkCameraPermissionAndGo() {
val hasCameraPermission = ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == android.content.pm.PackageManager.PERMISSION_GRANTED
if (hasCameraPermission) {
// 有权限,直接打开 MainActivity
goMainActivity()
} else {
// 无权限,请求相机权限
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
// 从设置页面返回后检查权限
private fun checkCameraPermissionAfterSettings() {
val hasCameraPermission = ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == android.content.pm.PackageManager.PERMISSION_GRANTED
if (hasCameraPermission) {
// 权限已授予,打开 MainActivity
goMainActivity()
} else {
// 权限仍未授予,再次显示弹窗
showPermissionDeniedDialog()
}
}
// 显示权限被拒绝的弹窗
private fun showPermissionDeniedDialog() {
RemindDialog(
context = context,
content = "暂无相机权限,请授权后重试",
confirmBlock = {
// 打开 App 设置页面
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = android.net.Uri.fromParts("package", packageName, null)
}
startSettingsLauncher.launch(intent)
}
).show()
}
private var checkNetworkTimer: CountDownTimer? = null
private fun initNetworkTimer() {
@@ -151,6 +151,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun initialize() {
super.initialize()
isPageVisible = true
// 拦截扫码枪按键事件,防止触发页面按钮点击
registerKeyEvent()
addBackEventListener()
initView()
if (SpTool.firstGetFace) {
@@ -921,8 +923,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// private val initialDelay = 5 * 60 * 1000L
// private val dealyMillis = 10 * 60 * 1000L
private val initialDelay = 30 * 1000L
private val dealyMillis = 3 * 60 * 1000L
private val initialDelay = 10 * 1000L
private val dealyMillis = 5 * 1000L
// private var taskPageNo = 1
fun startFaceTask() {
faceTaskJob =
@@ -1,6 +1,5 @@
package com.sw.dualscreen.activity
import android.view.KeyEvent
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
@@ -66,6 +65,7 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
var foodOrderId: String = ""
var eatNum: Int = 1
var isMember: Boolean = false
val presentation by lazy {
PayPresentation(
@@ -99,12 +99,14 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
binding.include.ivPageBack.setOnClickListener { finish() }
binding.include.tvPageTitle.text = "下单结算"
binding.btnPayQrCode.setOnClickListener {
isMember = false
if (binding.btnPayQrCode.isChecked) {
return@setOnClickListener
}
showScanQrCodePay()
}
binding.btnPayCash.setOnClickListener {
isMember = false
if (binding.btnPayCash.isChecked) {
return@setOnClickListener
}
@@ -160,7 +162,7 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
}
override fun onDestroy() {
presentation?.dismiss()
presentation.dismiss()
super.onDestroy()
}
@@ -175,14 +177,14 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
// display = displays[1],
// type = type
// ) {
// scanQrCodePayPresentation?.dismiss()
// scanQrCodePaypresentation.dismiss()
// }.also {
// it.foodName = foodInfo?.foodName
// //确认使用vipPrice 还是 specPrice
// val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice
// it.totalPrice = (onePrice ?: 0.0) * eatNum
// }
// scanQrCodePayPresentation?.show()
// scanQrCodePaypresentation.show()
// }
presentation.let {
it.pageType = PayPresentation.QR_CODE_PAY
@@ -196,8 +198,8 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
}
fun updateQrCodeImage(qrCodeUrl: String?) {
// scanQrCodePayPresentation?.loadQrCodeImage(qrCodeUrl)
presentation?.loadQrCodeImage(qrCodeUrl)
// scanQrCodePaypresentation.loadQrCodeImage(qrCodeUrl)
presentation.loadQrCodeImage(qrCodeUrl)
}
private var debouncer = Debouncer(5000)
@@ -240,7 +242,7 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
}
}
fun memberPay(param: HashMap<String, String>, block: () -> Unit) {
fun memberPay(param: HashMap<String, String?>, block: () -> Unit) {
userViewModel.memberPay(param) {
runOnUiThread {
if (it.not()) {
@@ -296,11 +298,11 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
fun qrCodePay(scanInfo: String) {
showWaitingDialog("支付中……")
userViewModel.qrCodePay(scanInfo, foodOrderId) { payState, backData ->
userViewModel.qrCodePay(scanInfo, foodOrderId, memberInfo?.id) { payState, backData ->
Timber.d("qrCodePay支付返回数据:state=$payState,backData=$backData")
hideWaitingDialog()
if (payState) {
showPaySuccess(false)
showPaySuccess(isMember)
}
}
@@ -32,6 +32,7 @@ class SettingActivity : BaseActivity<ActivitySettingBinding>() {
override fun initialize() {
super.initialize()
registerKeyEvent()
initBackDispatcher()
binding.include.let {
it.ivPageBack.setOnClickListener {
@@ -1,5 +1,7 @@
package com.sw.dualscreen.activity.fragment.pay
import android.text.InputType
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.activity.fragment.BaseFragment
import com.sw.dualscreen.databinding.FragmentNumberPayBinding
@@ -13,6 +15,8 @@ class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
private lateinit var payActivity: PayActivity
private var foodName: String? = null
private var payAmount: Double? = null
// 密码是否显示的标志
private var isPasswordVisible = false
override fun inflateViewBinding(): FragmentNumberPayBinding {
return FragmentNumberPayBinding.inflate(layoutInflater)
}
@@ -27,6 +31,12 @@ class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
foodName = it.foodName
payAmount = (it.specPrice ?: 0.0) * payActivity.eatNum
}
// 密码显示/隐藏切换
binding.ivTogglePassword.setOnClickListener {
togglePasswordVisibility()
}
binding.btnConfirm.setOnClickListener { v ->
val phone = binding.etInputPhone.text.toString().trim()
val key = binding.etInputNumber.text.toString().trim()
@@ -41,7 +51,7 @@ class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
// ToastUtils.showToast("会员验证成功")
// }
// }
payActivity.isMember = false
payActivity.getMemberInfoByPhone(phone, key) { memberInfo ->
if (memberInfo == null) {
binding.root.postDelayed({
@@ -52,6 +62,7 @@ class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
}
//肯定是会员
memberInfo.member = true
payActivity.isMember = true
//绑定订单使用faceUserId
payActivity.bindOrder(memberInfo.faceUserId ?: "") { bindResult ->
if (bindResult.not()) {
@@ -126,6 +137,30 @@ class NumberPayFragment : BaseFragment<FragmentNumberPayBinding>() {
}
}
// 切换密码显示/隐藏
private fun togglePasswordVisibility() {
val editText = binding.etInputNumber
val imageView = binding.ivTogglePassword
// 保存当前光标位置
val cursorPosition = editText.selectionStart
if (isPasswordVisible) {
// 当前显示,改为隐藏
editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
imageView.setImageResource(R.drawable.ic_eye_close)
isPasswordVisible = false
} else {
// 当前隐藏,改为显示
editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
imageView.setImageResource(R.drawable.ic_eye_open)
isPasswordVisible = true
}
// 恢复光标位置
editText.setSelection(cursorPosition)
}
// private fun bindOrder(userId: String, block: () -> Unit) {
// payActivity.bindOrder(userId) { bindResult ->
// if (bindResult.not()) {
@@ -289,7 +289,7 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
//订单号
"orderNo" to payActivity.foodOrderId,
//用户id
"memberId" to memberInfo!!.id!!
"memberId" to memberInfo?.id
),
block = callback
)
@@ -202,7 +202,7 @@ interface ApiService {
@POST
suspend fun memberPay(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/pay/app/memberPay",
@Body param: HashMap<String, String>
@Body param: HashMap<String, String?>
): ApiResponse<Any?>
/**
@@ -223,7 +223,7 @@ interface ApiService {
@POST
suspend fun qrCodePay(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/pay/app/qrCodePay",
@Body param: HashMap<String, String>
@Body param: HashMap<String, String?>
): ApiResponse<String?>
/**
@@ -143,6 +143,9 @@ object ObjectBox {
} catch (e: Exception) {
e.printStackTrace()
null
} finally {
// 线程资源清理
boxStore?.closeThreadResources()
}
}
}
@@ -177,16 +180,13 @@ object ObjectBox {
getBox<Food>()?.all
} ?: emptyList()
suspend fun filter(name: String?, isDistinct: Boolean = false) = safeDbOp {
val list = if (isDistinct) {
getBox<Food>()?.all?.distinctBy { it.foodName }
suspend fun filter(name: String?) = safeDbOp {
if (!name.isNullOrBlank()) {
getBox<Food>()?.query(Food_.foodName.contains(name))?.build()?.find()
?.distinctBy { it.foodName }
} else {
getBox<Food>()?.all
}
if (name.isNullOrBlank().not()) {
list?.filter { it.foodName?.contains(name) == true }
}
list
getBox<Food>()?.all?.distinctBy { it.foodName }
} ?: emptyList()
} ?: emptyList()
suspend fun removeAll() = safeDbOp {
@@ -194,10 +194,7 @@ object ObjectBox {
}
suspend fun remove(name: String) = safeDbOp {
getBox<Food>()?.run {
val filterIdList = all.filter { it.foodName == name }.map { it.id }
removeByIds(filterIdList)
}
getBox<Food>()?.query(Food_.foodName.equal(name))?.build()?.remove()
}
private val dbMutex = Mutex() // 协程并发锁,保证写入操作原子性
@@ -207,9 +204,7 @@ object ObjectBox {
// 检查存储是否可读写(操作数据库前调用)
fun isStorageAvailable(context: Context): Boolean {
return try {
val state = Environment.getExternalStorageState()
val innerDir = context.filesDir
Environment.MEDIA_MOUNTED == state && innerDir.canRead() && innerDir.canWrite()
context.filesDir.canRead() && context.filesDir.canWrite()
} catch (e: Exception) {
false
}
@@ -2,7 +2,6 @@ package com.sw.dualscreen.presentation.pay
import android.Manifest
import android.annotation.SuppressLint
import android.app.Dialog
import android.app.Presentation
import android.content.pm.PackageManager
import android.graphics.Point
@@ -11,24 +10,20 @@ import android.os.Build
import android.os.Bundle
import android.text.Spanned
import android.text.SpannedString
import android.text.TextUtils
import android.text.style.AbsoluteSizeSpan
import android.view.Display
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.core.text.buildSpannedString
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.arcsoft.face.ErrorInfo
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.databinding.PresentationFacePayBinding
import com.sw.dualscreen.databinding.PresentationPayBinding
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.format2String
@@ -38,9 +33,7 @@ import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.TextBean
import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.utils.SpannedUtils
import com.sw.dualscreen.view.CustomDialog
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.ConfigUtil
@@ -58,6 +51,7 @@ import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.concurrent.atomic.AtomicBoolean
class PayPresentation(
val activity: PayActivity,
@@ -299,13 +293,16 @@ class PayPresentation(
.i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}")
// recognitionTime = System.currentTimeMillis()
// recognitionWeight = lastWeight
if (isExistNotPayOrder.get()) return@Observer
lastFaceTrackId = compareResult.trackId
val faceEntity = compareResult.faceEntity
val userId = faceEntity.userName
val isMember = faceEntity.userType == "1"
if (userId == null) return@Observer
activity.isMember = isMember
if (userId.isNullOrBlank()) return@Observer
// TODO: 测试支付用户id
// userId = "1987710988425662466"
isExistNotPayOrder.set(true)
faceRecSuccess(userId, isMember)
})
@@ -314,6 +311,7 @@ class PayPresentation(
})
}
private var isExistNotPayOrder = AtomicBoolean(false)
private fun initArcView() {
//在布局结束后才做初始化操作
@@ -605,6 +603,7 @@ class PayPresentation(
//ToastUtils.showToast("订单绑定失败")
return@bindOrder
}
binding.root.postDelayed({
activity.hideWaitingDialog()
// TODO: 测试 memberInfo.member是否返回正常数据---------------
@@ -76,6 +76,7 @@ class RemoteRepository constructor(
)
}
}
/**
* 获取人脸数据
*/
@@ -137,13 +138,15 @@ class RemoteRepository constructor(
pageSize: Int = 50
): ApiResponse<List<FoodInfo>> {
return safeApiCall {
apiService.getRestInfoFoodsByType(param = hashMapOf(
apiService.getRestInfoFoodsByType(
param = hashMapOf(
"name" to foodName,
"pageNum" to "$pageNum",
"pageSize" to "$pageSize",
//"订单来源权举:1-营养秤,2-档口
"deviceType" to "2"
))
)
)
}
}
@@ -189,12 +192,17 @@ class RemoteRepository constructor(
/**
* 二维码支付
*/
suspend fun qrCodePay(authCode: String,orderNo: String): ApiResponse<String?> {
suspend fun qrCodePay(
authCode: String,
orderNo: String,
memberId: String?
): ApiResponse<String?> {
return safeApiCall {
apiService.qrCodePay(
param = hashMapOf(
"authCode" to authCode,
"outTradeNo" to orderNo,
"memberId" to memberId,
"orderType" to "0"
)
)
@@ -262,7 +270,7 @@ class RemoteRepository constructor(
/**
* 会员支付
*/
suspend fun memberPay(param: HashMap<String, String>): ApiResponse<Any?> {
suspend fun memberPay(param: HashMap<String, String?>): ApiResponse<Any?> {
return safeApiCall {
apiService.memberPay(param = param)
}
@@ -291,10 +299,12 @@ class RemoteRepository constructor(
*/
suspend fun getMemberInfoByPhone(phone: String, key: String): ApiResponse<MemberInfo?> {
return safeApiCall {
apiService.getMemberInfoByPhone(param = hashMapOf(
apiService.getMemberInfoByPhone(
param = hashMapOf(
"phone" to phone,
"password" to key
))
)
)
}
}
@@ -334,10 +344,12 @@ class RemoteRepository constructor(
suspend fun deleteCollectFood(foodId: String?, version: String?): ApiResponse<Any?> {
return safeApiCall {
apiService.deleteCollectFood(param = mutableMapOf(
apiService.deleteCollectFood(
param = mutableMapOf(
"foodId" to foodId,
"version" to version
))
)
)
}
}
}
@@ -363,9 +363,14 @@ class UserViewModel : BaseViewModel() {
/**
* 二维码支付
*/
fun qrCodePay(authCode: String,orderNo: String, block:(Boolean, String?)-> Unit){
fun qrCodePay(
authCode: String,
orderNo: String,
memberId: String?,
block: (Boolean, String?) -> Unit
) {
launch {
val response = repository.qrCodePay(authCode, orderNo)
val response = repository.qrCodePay(authCode, orderNo, memberId)
if (parseResponse(response)) {
block(true, response.data)
} else {
@@ -373,6 +378,7 @@ class UserViewModel : BaseViewModel() {
}
}
}
fun getDinnerType() {
Timber.tag(TAG).d("getDinnerType")
_dinnerTypeInfo.value = null
@@ -491,7 +497,7 @@ class UserViewModel : BaseViewModel() {
/**
* 会员支付
*/
fun memberPay(param: HashMap<String, String>, block: (Boolean) -> Unit) {
fun memberPay(param: HashMap<String, String?>, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("memberPay")
launchWithLoading {
val response = repository.memberPay(param)
@@ -588,7 +594,10 @@ class UserViewModel : BaseViewModel() {
}
}
fun getCollectedFoodVector(param: MutableMap<String, String>, block: (List<FoodVector>?) -> Unit) {
fun getCollectedFoodVector(
param: MutableMap<String, String>,
block: (List<FoodVector>?) -> Unit
) {
Timber.tag(TAG).d("getCollectedFoodVector")
launchWithLoading {
val response = repository.getCollectedFoodVector(param)
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!-- 眼睛轮廓 -->
<path
android:fillColor="@android:color/transparent"
android:strokeColor="@android:color/black"
android:strokeWidth="1.5"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:pathData="M 2 12 C 2 12 5 6 12 6 C 19 6 22 12 22 12 C 22 12 19 18 12 18 C 5 18 2 12 2 12 Z" />
<!-- 瞳孔(path绘制圆形) -->
<path
android:fillColor="@android:color/black"
android:pathData="M 12 9 C 13.66 9 15 10.34 15 12 C 15 13.66 13.66 15 12 15 C 10.34 15 9 13.66 9 12 C 9 10.34 10.34 9 12 9 Z" />
<!-- 斜线表示隐藏 -->
<path
android:fillColor="@android:color/transparent"
android:strokeColor="@android:color/black"
android:strokeWidth="1.5"
android:strokeLineCap="round"
android:pathData="M 4 4 L 20 20" />
</vector>
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!-- 眼睛轮廓 -->
<path
android:fillColor="@android:color/transparent"
android:strokeColor="@android:color/black"
android:strokeWidth="1.5"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:pathData="M 2 12 C 2 12 5 6 12 6 C 19 6 22 12 22 12 C 22 12 19 18 12 18 C 5 18 2 12 2 12 Z" />
<!-- 瞳孔(path绘制圆形) -->
<path
android:fillColor="@android:color/black"
android:pathData="M 12 9 C 13.66 9 15 10.34 15 12 C 15 13.66 13.66 15 12 15 C 10.34 15 9 13.66 9 12 C 9 10.34 10.34 9 12 9 Z" />
</vector>
+2 -5
View File
@@ -11,16 +11,14 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:background="@drawable/setting_border"
android:orientation="vertical"
android:paddingBottom="16dp">
<TextView
android:id="@+id/tvChargeSetting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="32dp"
android:layout_marginTop="35dp"
android:layout_marginTop="30dp"
android:drawablePadding="17dp"
android:text="餐品采集"
android:textColor="@color/black"
@@ -34,7 +32,6 @@
android:id="@+id/btnCollectedFood"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="32dp"
android:gravity="center_vertical"
android:includeFontPadding="false"
@@ -51,7 +48,7 @@
android:id="@+id/flPreview"
android:layout_width="456dp"
android:layout_height="342dp"
android:layout_marginTop="41dp"
android:layout_marginTop="30dp"
app:layout_constraintStart_toStartOf="@id/tvChargeSetting"
app:layout_constraintTop_toBottomOf="@id/tvChargeSetting">
@@ -34,17 +34,21 @@
android:textStyle="bold"
tools:ignore="Autofill,HardcodedText,LabelFor,TextFields" />
<EditText
android:id="@+id/etInputNumber"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginHorizontal="64dp"
android:inputType="textVisiblePassword"
android:layout_marginTop="32dp">
<EditText
android:id="@+id/etInputNumber"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="textPassword"
android:background="@drawable/setting_border_gray3"
android:hint="输入消费码"
android:textColorHint="#ffc4cfda"
android:textColor="#ff0a1428"
android:layout_marginTop="32dp"
android:textSize="36sp"
android:gravity="center"
android:maxLines="1"
@@ -53,6 +57,19 @@
android:textStyle="bold"
tools:ignore="Autofill,HardcodedText,LabelFor,TextFields" />
<ImageView
android:id="@+id/ivTogglePassword"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical|end"
android:paddingEnd="16dp"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_eye_close"
android:scaleType="centerInside"
tools:ignore="HardcodedText" />
</FrameLayout>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnConfirm"
android:layout_width="match_parent"