增加人脸采集功能;

识别人脸成功后打开有餐盘的第一个柜子;
扫码打开已绑定的柜子,无则打开第一个空柜子并放入餐盘;
设置页面问题优化;
This commit is contained in:
mazengfei
2026-01-14 19:00:20 +08:00
parent 11a0a41e3c
commit aadba7efd5
24 changed files with 1327 additions and 908 deletions
@@ -3,16 +3,20 @@ package com.sw.platecabinet
import android.util.Log
import com.sw.plate.App
import com.sw.plate.utils.AppUtil
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.utils.CrashHandler
import timber.log.Timber
class MyApp : App() {
companion object {
const val DEBUG: Boolean = true
var instance: MyApp? = null
var plateList: List<EquipmentUserInfo>? = null
}
override fun onCreate() {
super.onCreate()
instance = this
Timber.plant(Timber.DebugTree())
Timber.d("初始化")
initGlobalData()
@@ -25,6 +25,7 @@ import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import com.sw.plate.utils.comn.SerialApi
import com.sw.plate.utils.comn.SerialPortManager
import com.sw.platecabinet.MyApp
import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.dialog.BalanceNotEnoughDialog
@@ -33,6 +34,7 @@ import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.UserFaceModel
import com.sw.platecabinet.utils.IntervalExecutor
import com.sw.platecabinet.utils.PermissionHelper
import com.sw.platecabinet.utils.PlateUtils
import com.sw.platecabinet.utils.SpTool
import com.sw.platecabinet.view.CustomLoadingDialog
import com.sw.platecabinet.viewmodel.SettingViewModel
@@ -106,7 +108,34 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
* 处理扫描枪数据
*/
protected open fun handleScanKeyInfo(scanInfo: String) {
settingViewModel.findByPlateNumber(plateNumber = scanInfo)
// settingViewModel.findByPlateNumber(plateNumber = scanInfo)
var plateNumber = scanInfo
if (scanInfo.length > 6) {
plateNumber = scanInfo.take(6)
}
// ToastUtils.showToast(plateNumber)
var item = MyApp.plateList?.firstOrNull { it.plateNumber == plateNumber }
if (item == null) {
//柜子未关联该餐盘,直接找空位置放入盘子
item = MyApp.plateList?.firstOrNull { it.plateNumber.isNullOrBlank() }
if (item ==null) {
//柜子已满
MainActivity.start(context = context, pageType = PageType.PLATE_CABINET_FULL)
return
}
//找到位置,放入餐盘,清除已有id和时间
item.plateNumber = plateNumber
item.faceId = null
item.updateTime = null
PlateUtils.open(this, item.equipmentBoxCode)
return
}
//放入餐盘,清除已有id和时间
item.plateNumber = plateNumber
item.faceId = null
item.updateTime = null
PlateUtils.open(this, item.equipmentBoxCode)
SpTool.savePlateData(MyApp.plateList!!)
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@@ -279,7 +308,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
lifecycleScope.launch {
viewModel.currentUserInfo.collect {
if (it == null) return@collect
it.showBalanceNotEnoughDialog = true
// it.showBalanceNotEnoughDialog = true
handleLoginSuccess(it, false)
}
}
@@ -329,57 +358,57 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
* @param isAdmin true 管理员 执行绑盘此操作 false 用户,提示错误
*/
open fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
Timber.d("handleLoginSuccess isAdmin = $isAdmin")
equipmentUserInfo.isIntercept = false
val cardBalance = equipmentUserInfo.cardBalance ?: 0.toDouble()
val balanceIsNotEnough = cardBalance <= 0.toDouble()
if (balanceIsNotEnough && equipmentUserInfo.showBalanceNotEnoughDialog) {
//提示余额不足弹窗
equipmentUserInfo.isIntercept = true
BalanceNotEnoughDialog(this).show()
return
}
viewModel.resetUserInfo()
// if (equipmentUserInfo.isOtherEquipment()) {
// MainActivity.start(
// context,
// pageType = PageType.PLATE_TIP,
// equipmentUserInfo = equipmentUserInfo,
// isAdmin
// )
// Timber.d("handleLoginSuccess isAdmin = $isAdmin")
// equipmentUserInfo.isIntercept = false
// val cardBalance = equipmentUserInfo.cardBalance ?: 0.toDouble()
// val balanceIsNotEnough = cardBalance <= 0.toDouble()
// if (balanceIsNotEnough && equipmentUserInfo.showBalanceNotEnoughDialog) {
// //提示余额不足弹窗
// equipmentUserInfo.isIntercept = true
// BalanceNotEnoughDialog(this).show()
// return
// }
if (equipmentUserInfo.equipmentBoxCode?.isNotEmpty() == true) {
SerialApi.openPlate(
equipmentUserInfo.equipmentBoxCode!!.toInt(),
object : SerialPortManager.SendCallback {
override fun onSuccess() {
MainActivity.start(
context,
pageType = PageType.PLATE_TIP,
isAdmin = isAdmin
)
}
override fun onFail(e: Exception?) {
ToastUtils.showToast("柜门打开失败")
}
})
} else {
if (isAdmin) {
settingViewModel.getEquipmentList {
loadEquipmentList(it)
}
} else {
Timber.d("无餐盘信息")
MainActivity.start(
context,
pageType = PageType.PLATE_TIP,
equipmentUserInfo = equipmentUserInfo,
isAdmin = isAdmin
)
}
}
// viewModel.resetUserInfo()
//// if (equipmentUserInfo.isOtherEquipment()) {
//// MainActivity.start(
//// context,
//// pageType = PageType.PLATE_TIP,
//// equipmentUserInfo = equipmentUserInfo,
//// isAdmin
//// )
//// return
//// }
// if (equipmentUserInfo.equipmentBoxCode?.isNotEmpty() == true) {
// SerialApi.openPlate(
// equipmentUserInfo.equipmentBoxCode!!.toInt(),
// object : SerialPortManager.SendCallback {
// override fun onSuccess() {
// MainActivity.start(
// context,
// pageType = PageType.PLATE_TIP,
// isAdmin = isAdmin
// )
// }
//
// override fun onFail(e: Exception?) {
// ToastUtils.showToast("柜门打开失败")
// }
// })
// } else {
// if (isAdmin) {
// settingViewModel.getEquipmentList {
// loadEquipmentList(it)
// }
// } else {
// Timber.d("无餐盘信息")
// MainActivity.start(
// context,
// pageType = PageType.PLATE_TIP,
// equipmentUserInfo = equipmentUserInfo,
// isAdmin = isAdmin
// )
// }
// }
}
override fun onDestroy() {
@@ -407,7 +436,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
private var faceTimestamp = 0L
private fun getFaceIncrementList() {
val timestamp = SpTool.getLastFaceTimestamp()
val timestamp = SpTool.lastFaceTimestamp
if (timestamp == 0L) {
return
}
@@ -422,15 +451,15 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
}
updateFaceData(list)
if (list.size >= settingViewModel.PAGE_SIZE) {
faceTimestamp = list.last().faceUpdateTimestamp?:0
faceTimestamp = list.last().faceUpdateTimestamp ?: 0
taskPageNo++
getFaceIncrementList()
return@runOnUiThread
}
if (list.isNotEmpty()) {
faceTimestamp = list.last().faceUpdateTimestamp?:0
faceTimestamp = list.last().faceUpdateTimestamp ?: 0
}
SpTool.setLastFaceTimestamp(faceTimestamp)
SpTool.lastFaceTimestamp = faceTimestamp
}
}
}
@@ -6,10 +6,13 @@ import androidx.activity.viewModels
import com.sw.plate.utils.AppUtil
import com.sw.plate.utils.ToastUtils
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.MyApp
import com.sw.platecabinet.databinding.ActivityDeviceInitBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.ext.gone
import com.sw.platecabinet.ext.invisible
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.utils.SpTool
import com.sw.platecabinet.viewmodel.SettingViewModel
/**
@@ -45,6 +48,7 @@ class DeviceInitActivity : BaseActivity<ActivityDeviceInitBinding>() {
// binding.root.postDelayed({
// goLoginActivity()
// }, 1000)
initPlateList()
showWaitingDialog("加载中……")
viewModel.getDeviceConfig { deviceConfig ->
runOnUiThread {
@@ -88,4 +92,23 @@ class DeviceInitActivity : BaseActivity<ActivityDeviceInitBinding>() {
}
private fun initPlateList() {
// SpTool.putString(SpTool.PLATE_BOX_DATA, "")
var list = SpTool.getPlateData()
if (list.isNullOrEmpty()) {
list = mutableListOf()
repeat(22) { index ->
list.add(
EquipmentUserInfo(
equipmentBoxCode = "${index + 1}",
// faceId = null,
// plateNumber = if (index == 4) "011075" else null,
// updateTime = null
)
)
}
}
MyApp.plateList = list
}
}
@@ -7,13 +7,21 @@ import android.hardware.Camera
import android.os.Build
import android.os.CountDownTimer
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.arcsoft.face.ErrorInfo
import com.google.gson.Gson
import com.sw.inbound.utils.DateTimeUtils
import com.sw.inbound.utils.GsonUtils
import com.sw.plate.App
import com.sw.plate.utils.Base64
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.ConfigUtil
import com.sw.plate.utils.arcface.ErrorCodeUtil
@@ -24,17 +32,31 @@ import com.sw.plate.utils.arcface.PreviewConfig
import com.sw.plate.utils.arcface.camera.CameraListener
import com.sw.plate.utils.arcface.camera.DualCameraHelper
import com.sw.plate.utils.arcface.face.constants.LivenessType
import com.sw.plate.utils.arcface.face.model.CompareResult
import com.sw.plate.utils.arcface.face.model.FacePreviewInfo
import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration
import com.sw.plate.utils.arcface.faceserver.FaceServer
import com.sw.plate.utils.arcface.facedb.FaceDatabase
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.plate.utils.arcface.model.UserFaceInfo
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel.REGISTER_STATUS_READY
import com.sw.platecabinet.MyApp
import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.ext.gone
import com.sw.platecabinet.ext.invisible
import com.sw.platecabinet.ext.visible
import com.sw.platecabinet.model.request.BindParam
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.network.task.TaskManager
import com.sw.platecabinet.utils.IntervalExecutor
import com.sw.platecabinet.utils.PermissionHelper
import com.sw.platecabinet.utils.PlateUtils
import com.sw.platecabinet.utils.SpTool
import com.sw.platecabinet.utils.countDownByFlow
import com.sw.platecabinet.viewmodel.SettingViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.runBlocking
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -64,6 +86,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
}
companion object {
private const val TAG = "LoginByFaceActivity"
private var instance: LoginByFaceActivity? = null
fun goInitActivity() {
@@ -82,17 +105,26 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
recognizeViewModel.setDrawRectInfoTextValue(true)
//viewModel.generateToken()
// viewModel.activeEngine()
viewModel.getUserFaceCache()
binding.llToPwd.setOnClickListener {
val intent = Intent(this, LoginByPwdActivity::class.java)
startActivity(intent)
}
// TODO: 暂时注释人脸接口数据,测试本地采集
// viewModel.getUserFaceCache()
// Thread {
// val faceDao = FaceDatabase.getInstance(App.getContext()).faceDao();
// faceDao.deleteAll()
// faceDao.resetId()
// }.start()
// TODO: 测试请求
TaskManager.startTask()
// binding.llToPwd.setOnClickListener {
// val intent = Intent(this, LoginByPwdActivity::class.java)
// startActivity(intent)
// }
// TaskManager.startTask()
EventBus.getDefault().register(this)
binding.btnCollectFace.setOnClickListener { collectFace() }
}
private fun checkCameraPermission() {
@@ -131,7 +163,11 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private fun initArcViewModel() {
recognizeViewModel.setLiveType(livenessType)
recognizeViewModel.prepareRegister()
recognizeViewModel.setOnRegisterFinishedCallback { facePreviewInfo, userFaceInfo ->
this.userFaceInfo = userFaceInfo
Log.d(TAG, "initArcViewModel: userFaceInfo == null : ${userFaceInfo == null}")
}
recognizeViewModel.ftInitCode.observe(this, Observer { ftInitCode: Int? ->
if (ftInitCode != ErrorInfo.MOK) {
val error: String? = getString(
@@ -171,9 +207,19 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Timber.i("recognizeNotice observe notice = $notice")
})
recognizeViewModel.recognizeUserId.observe(this, Observer { userId: String? ->
Timber.i("recognizeUserId observe userId = $userId")
viewModel.getUserInfoById(memberId = userId)
recognizeViewModel.recognizeUserId.observe(this, Observer { result: CompareResult? ->
Timber.i("recognizeUserId observe userId = ${result?.faceEntity?.userName}")
currentUserId = result?.faceEntity?.userName
// viewModel.getUserInfoById(memberId = userId)
//ToastUtils.showToast(userId)
// if (!currentUserId.isNullOrBlank()) {
//// ToastUtils.showToast("您已采集过人脸信息")
// return@Observer
// }
if (currentPlateInfo?.faceId == currentUserId) {
return@Observer
}
openPlate(currentUserId)
})
recognizeViewModel.drawRectInfoText.observe(this, Observer { info ->
@@ -181,6 +227,69 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
})
}
// private val settingViewModel by viewModels<SettingViewModel>()
/**
* 查询餐盘数据
*/
private fun getPlateData(block: (List<EquipmentUserInfo>) -> Unit) {
MyApp.plateList?.let {
block(it)
}
// settingViewModel.getEquipmentList { items ->
// block(items)
// }
}
private var currentPlateInfo: EquipmentUserInfo? = null
/**
* 打开餐盘柜
*/
private fun openPlate(userId: String?) {
getPlateData { items ->
Log.d(TAG, "openPlate: ${Gson().toJson(items)}")
var item = items.firstOrNull { it.faceId == userId }
if (item != null) {
//餐盘已取
ToastUtils.showToast("您已拿过餐盘!")
return@getPlateData
}
// 未查询到当前用户
item = items.firstOrNull { it.plateNumber.isNullOrEmpty().not() }
if (item == null) {
//暂无餐盘
ToastUtils.showToast("暂无餐盘,请联系管理人员!")
return@getPlateData
}
// TODO: 待定如何在设置页面显示plateNumber,可以增加字段处理
item.faceId = userId
item.updateTime = DateTimeUtils.getDateTimeString()
//打开柜子
PlateUtils.open(this, item.equipmentBoxCode)
currentPlateInfo = item
MyApp.plateList = items
SpTool.savePlateData(items)
}
}
// /**
// * 绑定餐盘
// */
// private fun bindPlate(item: EquipmentUserInfo) {
// val bindParam = BindParam(
// equipmentId = item.equipmentId,
// equipmentCode = item.equipmentCode,
// equipmentBoxCode = item.equipmentBoxCode,
// faceId = item.faceId,
// plateNumber = item.plateNumber
// )
// settingViewModel.bindPlate(bindParam) { pair ->
// Log.d(TAG, "openPlate: state:${pair.first},msg:${pair.second.code},${pair.second.msg}")
// }
// }
private fun initArcView() {
//在布局结束后才做初始化操作
binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this)
@@ -198,6 +307,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
recognizeViewModel.destroy()
EventBus.getDefault().unregister(this)
countDownJob?.cancel()
super.onDestroy()
}
@@ -320,6 +431,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
if (facePreviewInfoList != null && rgbFaceRectTransformer != null) {
drawPreviewInfo(facePreviewInfoList)
}
if (facePreviewInfoList.isNullOrEmpty()) {
currentPlateInfo = null
currentUserId = null
}
recognizeViewModel.clearLeftFace(facePreviewInfoList)
}
@@ -444,5 +559,100 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
startActivity(intent)
}
private fun collectFace() {
//toast("currentUserId=$currentUserId")
if (currentUserId != null) {
ToastUtils.showToast("您已采集过人脸信息")
return
}
currentUserId = null
userFaceInfo = null
recognizeViewModel.updateRegisterStatus(REGISTER_STATUS_READY)
//showWaitingDialog("人脸信息中……")
// binding.tvFaceTip.gone()
binding.btnCollectFace.invisible()
binding.layoutState.visible()
binding.pbCollectLoading.visible()
binding.tvCollectState.text = "采集中......"
getFaceData { faceData ->
Log.d("LoginByFaceActivity", "faceData: $faceData")
runOnUiThread {
//hideWaitingDialog()
//toast("人脸信息已采集")
binding.pbCollectLoading.gone()
//binding.tvCollectState.text = "采集完成"
userFaceInfo = null
countDown()
}
// sendFaceData(faceData)
saveFaceInfo(faceData)
}
}
private fun getFaceData(block: (String) -> Unit) {
runBlocking {
job = executor.startIntervalTask(5) {
// if (currentUserId != null && currentUserId!!.isNotBlank()) {
// toast("您已采集过人脸信息")
// return@startIntervalTask
// }
if (userFaceInfo == null) {
return@startIntervalTask
}
val faceData = Base64.encode(userFaceInfo!!.faceFeature!!.featureData)
block(faceData)
job?.cancel()
}
}
}
private var userFaceInfo: UserFaceInfo? = null
private var countDownJob: Job? = null
private var job: Job? = null
val executor = IntervalExecutor()
private var currentUserId: String? = null
private fun countDown() {
countDownJob = countDownByFlow(
total = 3,
scope = lifecycleScope,
onStart = {
binding.tvCollectState.text = "采集完成(3s"
},
onTick = { seconds ->
binding.tvCollectState.text = "采集完成(${seconds}s"
},
onFinish = {
//binding.tvCollectState.text = "采集完成"
currentUserId = null
binding.layoutState.invisible()
// binding.tvFaceTip.visible()
binding.btnCollectFace.visible()
}
)
}
private fun saveFaceInfo(faceData: String) {
Thread {
try {
val tempId = "${System.currentTimeMillis()}"
val faceEntity = FaceEntity(
tempId,
null,
Base64.decode(faceData)
).also {
it.userType = "2"
}
FaceDatabase.getInstance(this).faceDao().insert(faceEntity)
recognizeViewModel.refreshFaceList();
runOnUiThread {
ToastUtils.showToast("你的人脸信息已采集")
}
} catch (e: Exception) {
e.printStackTrace()
}
}.start()
}
}
@@ -1,62 +1,62 @@
package com.sw.platecabinet.activity
import android.content.Intent
import com.sw.plate.utils.ToastUtils
import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.dialog.BalanceNotEnoughDialog
import com.sw.platecabinet.model.request.LoginParam
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.utils.KeyboardUtils
/**
* 密码登录
*/
class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
override fun inflateViewBinding(): ActivityLoginByPwdBinding {
return ActivityLoginByPwdBinding.inflate(layoutInflater)
}
override fun inflateTitleBinding(): ItemTitleTimeBinding {
return binding.includeHeader
}
override fun initialize() {
binding.btnLogin.setOnClickListener {
val phone = binding.etPhone.text.toString()
val pwd = binding.etPwd.text.toString()
if (phone.isEmpty() || pwd.isEmpty()) {
ToastUtils.showToast("手机或校验码不能为空")
return@setOnClickListener
}
val loginParam = LoginParam(
//equipmentId = equipmentId,
phone = phone,
password = pwd
)
viewModel.loginWithPwd(loginParam)
KeyboardUtils.hideKeyboard(this)
}
binding.tvFaceRec.setOnClickListener {
val intent = Intent(this, LoginByFaceActivity::class.java)
startActivity(intent)
}
}
override fun onResume() {
super.onResume()
viewModel.resetUserInfo()
}
override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
super.handleLoginSuccess(equipmentUserInfo, isAdmin)
// val cardBalance = equipmentUserInfo.cardBalance?:0.toDouble()
// val balanceIsNotEnough = cardBalance <= 0.toDouble()
if (equipmentUserInfo.isIntercept) {
return
}
LoginByFaceActivity.goInitActivity()
finish()
}
}
//package com.sw.platecabinet.activity
//
//import android.content.Intent
//import com.sw.plate.utils.ToastUtils
//import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding
//import com.sw.platecabinet.databinding.ItemTitleTimeBinding
//import com.sw.platecabinet.dialog.BalanceNotEnoughDialog
//import com.sw.platecabinet.model.request.LoginParam
//import com.sw.platecabinet.model.response.EquipmentUserInfo
//import com.sw.platecabinet.utils.KeyboardUtils
//
///**
// * 密码登录
// */
//class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
//
// override fun inflateViewBinding(): ActivityLoginByPwdBinding {
// return ActivityLoginByPwdBinding.inflate(layoutInflater)
// }
//
// override fun inflateTitleBinding(): ItemTitleTimeBinding {
// return binding.includeHeader
// }
//
// override fun initialize() {
// binding.btnLogin.setOnClickListener {
// val phone = binding.etPhone.text.toString()
// val pwd = binding.etPwd.text.toString()
// if (phone.isEmpty() || pwd.isEmpty()) {
// ToastUtils.showToast("手机或校验码不能为空")
// return@setOnClickListener
// }
// val loginParam = LoginParam(
// //equipmentId = equipmentId,
// phone = phone,
// password = pwd
// )
// viewModel.loginWithPwd(loginParam)
// KeyboardUtils.hideKeyboard(this)
// }
// binding.tvFaceRec.setOnClickListener {
// val intent = Intent(this, LoginByFaceActivity::class.java)
// startActivity(intent)
// }
// }
//
// override fun onResume() {
// super.onResume()
// viewModel.resetUserInfo()
// }
//
// override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
// super.handleLoginSuccess(equipmentUserInfo, isAdmin)
//// val cardBalance = equipmentUserInfo.cardBalance?:0.toDouble()
//// val balanceIsNotEnough = cardBalance <= 0.toDouble()
// if (equipmentUserInfo.isIntercept) {
// return
// }
// LoginByFaceActivity.goInitActivity()
// finish()
// }
//}
@@ -2,14 +2,13 @@ package com.sw.platecabinet.activity
import android.content.Context
import android.content.Intent
import com.sw.platecabinet.MyApp
import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ActivityMainBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.fragment.BindPlateFragment
import com.sw.platecabinet.fragment.PlateCabinetFullFragment
import com.sw.platecabinet.fragment.PlateOpenFragment
import com.sw.platecabinet.fragment.SettingListFragment
import com.sw.platecabinet.fragment.UnBindPlateFragment
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.utils.FragmentHelper
@@ -58,12 +57,15 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
fragmentHelper = FragmentHelper(supportFragmentManager, R.id.fragment_container)
val page = when (pageType) {
PageType.SETTING_LIST -> SettingListFragment()
PageType.BIND_PLATE -> BindPlateFragment.newInstance(equipmentUserInfo)
// PageType.BIND_PLATE -> BindPlateFragment.newInstance(equipmentUserInfo)
PageType.PLATE_TIP -> PlateOpenFragment.newInstance(equipmentUserInfo, isAdmin)
PageType.UNBIND_PLATE -> UnBindPlateFragment.newInstance(equipmentUserInfo)
// PageType.UNBIND_PLATE -> UnBindPlateFragment.newInstance(equipmentUserInfo)
PageType.PLATE_CABINET_FULL -> PlateCabinetFullFragment()
else -> null
}
page?.let {
fragmentHelper.addFragment(it)
}
fragmentHelper.addFragment(page)
}
override fun onLeftDoubleClick() {
@@ -1,57 +1,57 @@
package com.sw.platecabinet.activity
import android.graphics.Color
import android.view.Gravity
import android.view.ViewGroup
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.WindowCompat
import com.sw.platecabinet.GlobalKey
import com.sw.platecabinet.databinding.ActivityUnbindDialogBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.ext.dp
import com.sw.platecabinet.model.response.EquipmentUserInfo
/**
* 解绑确认弹窗界面
*/
class UnBindDialogActivity : BaseActivity<ActivityUnbindDialogBinding>() {
private var equipmentUserInfo: EquipmentUserInfo? = null
override fun inflateViewBinding(): ActivityUnbindDialogBinding {
return ActivityUnbindDialogBinding.inflate(layoutInflater)
}
override fun inflateTitleBinding(): ItemTitleTimeBinding? {
return null
}
override fun initialize() {
window?.apply {
WindowCompat.setDecorFitsSystemWindows(this, false)
setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
attributes = attributes.apply {
y = 314.dp
width = (context.resources.displayMetrics.widthPixels * 0.8).toInt()
height = ViewGroup.LayoutParams.MATCH_PARENT
gravity = Gravity.CENTER
}
}
equipmentUserInfo =
intent.getParcelableExtra<EquipmentUserInfo>(GlobalKey.PARAM_EQUIPMENT_INFO)
if (equipmentUserInfo == null) return
binding.tvTipInfo.text = "即将解除【${equipmentUserInfo!!.name}】的餐盘"
binding.tvCancel.setOnClickListener {
finish()
}
binding.tvConfirm.setOnClickListener {
setResult(RESULT_OK)
finish()
}
}
override fun finish() {
super.finish()
overridePendingTransition(0, 0) // 确保退出也无动画
}
}
//package com.sw.platecabinet.activity
//
//import android.graphics.Color
//import android.view.Gravity
//import android.view.ViewGroup
//import androidx.core.graphics.drawable.toDrawable
//import androidx.core.view.WindowCompat
//import com.sw.platecabinet.GlobalKey
//import com.sw.platecabinet.databinding.ActivityUnbindDialogBinding
//import com.sw.platecabinet.databinding.ItemTitleTimeBinding
//import com.sw.platecabinet.ext.dp
//import com.sw.platecabinet.model.response.EquipmentUserInfo
//
///**
// * 解绑确认弹窗界面
// */
//class UnBindDialogActivity : BaseActivity<ActivityUnbindDialogBinding>() {
// private var equipmentUserInfo: EquipmentUserInfo? = null
//
// override fun inflateViewBinding(): ActivityUnbindDialogBinding {
// return ActivityUnbindDialogBinding.inflate(layoutInflater)
// }
//
// override fun inflateTitleBinding(): ItemTitleTimeBinding? {
// return null
// }
//
// override fun initialize() {
// window?.apply {
// WindowCompat.setDecorFitsSystemWindows(this, false)
// setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
//
// attributes = attributes.apply {
// y = 314.dp
// width = (context.resources.displayMetrics.widthPixels * 0.8).toInt()
// height = ViewGroup.LayoutParams.MATCH_PARENT
// gravity = Gravity.CENTER
// }
// }
// equipmentUserInfo =
// intent.getParcelableExtra<EquipmentUserInfo>(GlobalKey.PARAM_EQUIPMENT_INFO)
// if (equipmentUserInfo == null) return
// binding.tvTipInfo.text = "即将解除【${equipmentUserInfo!!.name}】的餐盘"
// binding.tvCancel.setOnClickListener {
// finish()
// }
// binding.tvConfirm.setOnClickListener {
// setResult(RESULT_OK)
// finish()
// }
// }
//
// override fun finish() {
// super.finish()
// overridePendingTransition(0, 0) // 确保退出也无动画
// }
//}
@@ -1,317 +1,317 @@
package com.sw.platecabinet.fragment
import android.annotation.SuppressLint
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.view.inputmethod.EditorInfo
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.comn.SerialApi
import com.sw.plate.utils.comn.SerialPortManager
import com.sw.platecabinet.R
import com.sw.platecabinet.activity.MainActivity
import com.sw.platecabinet.activity.PageType
import com.sw.platecabinet.adapter.GenericItemAdapter
import com.sw.platecabinet.adapter.GridSpacingItemDecoration
import com.sw.platecabinet.adapter.dpToPx
import com.sw.platecabinet.databinding.FragmentBindPlateBinding
import com.sw.platecabinet.databinding.ItemSearchUserInfoBinding
import com.sw.platecabinet.dialog.UserBindRemindDialog
import com.sw.platecabinet.ext.maskName
import com.sw.platecabinet.ext.maskPhone
import com.sw.platecabinet.model.ErrorInfo
import com.sw.platecabinet.model.request.BindParam
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.utils.Debouncer
import com.sw.platecabinet.utils.KeyboardUtils
import com.sw.platecabinet.viewmodel.SettingViewModel
import com.sw.platecabinet.viewmodel.UserViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
/**
* 餐盘柜绑定
*/
class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
FragmentBindPlateBinding::inflate
) {
private lateinit var adapter: GenericItemAdapter<SearchResult.Member, ItemSearchUserInfoBinding>
internal val KEY_ACTION_TYPE = "actionType"
private var info: EquipmentUserInfo? = null
private var checkedItem: SearchResult.Member? = null
private var lastText = ""
private val debouncer = Debouncer(2000)
private val userViewModel by viewModels<UserViewModel>()
companion object {
@JvmStatic
fun newInstance(userInfo: EquipmentUserInfo?) =
BindPlateFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_ACTION_TYPE, userInfo)
}
}
}
@SuppressLint("SetTextI18n")
override fun initialize() {
arguments?.let { args ->
info = args.getParcelable(KEY_ACTION_TYPE)
info?.let {
binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}"
if (!TextUtils.isEmpty(it.plateNumber)) {
// binding.etCode.text = Editable.Factory.getInstance().newEditable(it.plateNumber)
binding.etCode.apply {
setText(it.plateNumber)
setSelection(length())
}
}
}
}
initView()
initListener()
}
private fun initView() {
adapter = createAdapter()
binding.recyclerview.layoutManager = GridLayoutManager(context, 2)
// 添加间距装饰(12dp)
binding.recyclerview.addItemDecoration(
GridSpacingItemDecoration(
spanCount = 2,
spacing = requireContext().dpToPx(6),
includeEdge = false // 包含边缘间距
)
)
binding.recyclerview.adapter = adapter
binding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
val totalItems = layoutManager.itemCount
if (!viewModel.isLoading && viewModel.canLoadMore
&& lastVisibleItem >= totalItems - 3
) {
viewModel.getSearchMemberList(
param = lastText,
pageNum = viewModel.currentPage
)
}
}
})
(activity as MainActivity).registerKeyEventInfo {
// binding.etCode.text.clear()
// binding.etCode.postDelayed({
// binding.etCode.text.clear()
// binding.etCode.text = Editable.Factory.getInstance().newEditable(it)
activity?.runOnUiThread {
if (binding.etUserInfo.isFocused) {
return@runOnUiThread
}
binding.etCode.apply {
if (it.length > 6) {
setText(it.substring(0, 6))
} else {
setText(it)
}
if (length() > 0) {
setSelection(length())
}
}
binding.etUserInfo.requestFocus()
}
// }, 50)
}
}
private fun initListener() {
binding.etCode.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
Timber.d("beforeTextChanged s = ${s.toString()}, start = $start, count = $count, after = $after")
}
override fun onTextChanged(
s: CharSequence?,
start: Int,
before: Int,
count: Int
) {
Timber.d("onTextChanged s = ${s.toString()}, start = $start, count = $count, before = $before")
}
override fun afterTextChanged(s: Editable?) {
Timber.d("afterTextChanged s = ${s.toString()}")
}
})
binding.etUserInfo.setOnEditorActionListener { _, actionId, keyEvent ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
val currentText = binding.etUserInfo.text.toString()
val containsNewlines = currentText.contains('\n') || currentText.contains('\r')
if (containsNewlines) {
Timber.d("非用户主动搜索")
true
}
debouncer.debounce {
// 执行搜索操作
viewModel.getSearchMemberList(param = currentText, pageNum = 1)
// 隐藏键盘
KeyboardUtils.hideKeyboard(requireActivity())
}
true // 表示已处理该事件
} else {
false // 未处理其他动作
}
}
binding.ivSearch.setOnClickListener {
debouncer.debounce {
// 执行搜索操作
viewModel.getSearchMemberList(
param = binding.etUserInfo.text.toString(),
pageNum = 1
)
// 隐藏键盘
KeyboardUtils.hideKeyboard(requireActivity())
}
}
binding.llBind.setOnClickListener {
if (equipmentBoxCode.isNullOrBlank().not()) {
showBindDialog()
return@setOnClickListener
}
if (info == null || info!!.equipmentCode?.isEmpty() == true || info!!.equipmentBoxCode?.isEmpty() == true) {
ToastUtils.showToast("传入的设备信息异常")
return@setOnClickListener
}
val plateNumber = binding.etCode.text.toString()
if (plateNumber.isEmpty()) {
ToastUtils.showToast("请输入餐盘号")
return@setOnClickListener
}
if (checkedItem == null) {
ToastUtils.showToast("请选择要绑定的会员")
return@setOnClickListener
}
if (checkedItem!!.id == null) {
ToastUtils.showToast("选中的会员信息异常")
return@setOnClickListener
}
val bindParam = BindParam(
equipmentId = info?.equipmentId,
equipmentCode = info?.equipmentCode,
equipmentBoxCode = info?.equipmentBoxCode,
faceId = checkedItem?.faceId,
plateNumber = plateNumber
)
viewModel.bindPlate(bindParam) { pair ->
updateBindState(pair)
}
KeyboardUtils.hideKeyboard(requireActivity())
}
binding.tvBack.setOnClickListener { activity?.finish() }
}
/**
* 监听数据变化
*/
override fun registerDataChange() {
super.registerDataChange()
lifecycleScope.launch {
viewModel.searchMemberList.collect {
adapter.updateData(it)
}
}
// lifecycleScope.launch {
// viewModel.bindStateChange.collect {
// updateBindState(it)
//package com.sw.platecabinet.fragment
//
//import android.annotation.SuppressLint
//import android.os.Bundle
//import android.text.Editable
//import android.text.TextUtils
//import android.text.TextWatcher
//import android.view.inputmethod.EditorInfo
//import androidx.fragment.app.viewModels
//import androidx.lifecycle.lifecycleScope
//import androidx.recyclerview.widget.GridLayoutManager
//import androidx.recyclerview.widget.LinearLayoutManager
//import androidx.recyclerview.widget.RecyclerView
//import com.sw.plate.utils.ToastUtils
//import com.sw.plate.utils.comn.SerialApi
//import com.sw.plate.utils.comn.SerialPortManager
//import com.sw.platecabinet.R
//import com.sw.platecabinet.activity.MainActivity
//import com.sw.platecabinet.activity.PageType
//import com.sw.platecabinet.adapter.GenericItemAdapter
//import com.sw.platecabinet.adapter.GridSpacingItemDecoration
//import com.sw.platecabinet.adapter.dpToPx
//import com.sw.platecabinet.databinding.FragmentBindPlateBinding
//import com.sw.platecabinet.databinding.ItemSearchUserInfoBinding
//import com.sw.platecabinet.dialog.UserBindRemindDialog
//import com.sw.platecabinet.ext.maskName
//import com.sw.platecabinet.ext.maskPhone
//import com.sw.platecabinet.model.ErrorInfo
//import com.sw.platecabinet.model.request.BindParam
//import com.sw.platecabinet.model.response.EquipmentUserInfo
//import com.sw.platecabinet.model.response.SearchResult
//import com.sw.platecabinet.utils.Debouncer
//import com.sw.platecabinet.utils.KeyboardUtils
//import com.sw.platecabinet.viewmodel.SettingViewModel
//import com.sw.platecabinet.viewmodel.UserViewModel
//import kotlinx.coroutines.launch
//import timber.log.Timber
//
///**
// * 餐盘柜绑定
// */
//class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
// FragmentBindPlateBinding::inflate
//) {
// private lateinit var adapter: GenericItemAdapter<SearchResult.Member, ItemSearchUserInfoBinding>
// internal val KEY_ACTION_TYPE = "actionType"
// private var info: EquipmentUserInfo? = null
// private var checkedItem: SearchResult.Member? = null
// private var lastText = ""
// private val debouncer = Debouncer(2000)
//
// private val userViewModel by viewModels<UserViewModel>()
//
// companion object {
// @JvmStatic
// fun newInstance(userInfo: EquipmentUserInfo?) =
// BindPlateFragment().apply {
// arguments = Bundle().apply {
// putParcelable(KEY_ACTION_TYPE, userInfo)
// }
// }
// }
//
// @SuppressLint("SetTextI18n")
// override fun initialize() {
// arguments?.let { args ->
// info = args.getParcelable(KEY_ACTION_TYPE)
// info?.let {
// binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}"
// if (!TextUtils.isEmpty(it.plateNumber)) {
//// binding.etCode.text = Editable.Factory.getInstance().newEditable(it.plateNumber)
// binding.etCode.apply {
// setText(it.plateNumber)
// setSelection(length())
// }
// }
// }
// }
}
private fun createAdapter(): GenericItemAdapter<SearchResult.Member, ItemSearchUserInfoBinding> {
return GenericItemAdapter(
items = emptyList(),
bindingInflater = ItemSearchUserInfoBinding::inflate,
bindCallback = { item, position ->
this.tvName.text = item.name.maskName()
this.tvPhone.text = item.phone.maskPhone()
if (item.id != checkedItem?.id) {
this.llRoot.setBackgroundResource(R.drawable.grid_item_bind)
} else {
this.llRoot.setBackgroundResource(R.drawable.grid_item_unbind)
}
this.llRoot.setOnClickListener {
Timber.d("itemClick ${item.name}, position = $position")
checkedItem = item
adapter.notifyDataSetChanged()
//TODO 调用接口查询用户是否已绑盘
this@BindPlateFragment.equipmentBoxCode = null
(activity as? MainActivity)?.showWaitingDialog("查询中,请稍后……")
userViewModel.getUserInfoById(memberId = item.faceId) {
(activity as? MainActivity)?.hideWaitingDialog()
this@BindPlateFragment.equipmentBoxCode = it?.equipmentBoxCode
}
}
}
)
}
private var equipmentBoxCode:String? = null
private fun showBindDialog() {
UserBindRemindDialog(
activity = requireActivity(),
content = "您已绑定编号为${equipmentBoxCode}的柜子,请解绑后重试"
)
.show()
}
private fun updateBindState(pair: Pair<Boolean?, ErrorInfo>){
if (pair.first == null) return // 解绑状态过滤
val errorInfo = pair.second
if (errorInfo.isSuccess()) {
if (errorInfo.equipmentUserInfo == null) {
ToastUtils.showToast("数据异常")
return
}
// if (errorInfo.equipmentUserInfo.isOtherEquipment()) {
// MainActivity.start(
// requireContext(),
// pageType = PageType.PLATE_TIP,
// equipmentUserInfo = errorInfo.equipmentUserInfo,
// isAdmin = true
// )
// } else {
SerialApi.openPlate(
errorInfo.equipmentUserInfo.equipmentBoxCode!!.toInt(),
object : SerialPortManager.SendCallback {
override fun onSuccess() {
ToastUtils.showToast("绑定成功")
activity?.finish()
}
override fun onFail(e: Exception?) {
ToastUtils.showToast("绑定失败")
}
})
// initView()
// initListener()
// }
//
// private fun initView() {
// adapter = createAdapter()
// binding.recyclerview.layoutManager = GridLayoutManager(context, 2)
// // 添加间距装饰(12dp)
// binding.recyclerview.addItemDecoration(
// GridSpacingItemDecoration(
// spanCount = 2,
// spacing = requireContext().dpToPx(6),
// includeEdge = false // 包含边缘间距
// )
// )
// binding.recyclerview.adapter = adapter
// binding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() {
// override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
// super.onScrolled(recyclerView, dx, dy)
// val layoutManager = recyclerView.layoutManager as LinearLayoutManager
// val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
// val totalItems = layoutManager.itemCount
//
// if (!viewModel.isLoading && viewModel.canLoadMore
// && lastVisibleItem >= totalItems - 3
// ) {
// viewModel.getSearchMemberList(
// param = lastText,
// pageNum = viewModel.currentPage
// )
// }
// }
} else {
ToastUtils.showToast(errorInfo.msg)
}
}
}
// })
// (activity as MainActivity).registerKeyEventInfo {
//// binding.etCode.text.clear()
//// binding.etCode.postDelayed({
//// binding.etCode.text.clear()
//// binding.etCode.text = Editable.Factory.getInstance().newEditable(it)
// activity?.runOnUiThread {
// if (binding.etUserInfo.isFocused) {
// return@runOnUiThread
// }
// binding.etCode.apply {
// if (it.length > 6) {
// setText(it.substring(0, 6))
// } else {
// setText(it)
// }
// if (length() > 0) {
// setSelection(length())
// }
// }
// binding.etUserInfo.requestFocus()
// }
//// }, 50)
// }
// }
//
// private fun initListener() {
// binding.etCode.addTextChangedListener(object : TextWatcher {
// override fun beforeTextChanged(
// s: CharSequence?,
// start: Int,
// count: Int,
// after: Int
// ) {
// Timber.d("beforeTextChanged s = ${s.toString()}, start = $start, count = $count, after = $after")
// }
//
// override fun onTextChanged(
// s: CharSequence?,
// start: Int,
// before: Int,
// count: Int
// ) {
// Timber.d("onTextChanged s = ${s.toString()}, start = $start, count = $count, before = $before")
// }
//
// override fun afterTextChanged(s: Editable?) {
// Timber.d("afterTextChanged s = ${s.toString()}")
// }
// })
// binding.etUserInfo.setOnEditorActionListener { _, actionId, keyEvent ->
// if (actionId == EditorInfo.IME_ACTION_SEARCH) {
// val currentText = binding.etUserInfo.text.toString()
// val containsNewlines = currentText.contains('\n') || currentText.contains('\r')
// if (containsNewlines) {
// Timber.d("非用户主动搜索")
// true
// }
// debouncer.debounce {
// // 执行搜索操作
// viewModel.getSearchMemberList(param = currentText, pageNum = 1)
// // 隐藏键盘
// KeyboardUtils.hideKeyboard(requireActivity())
// }
// true // 表示已处理该事件
// } else {
// false // 未处理其他动作
// }
// }
// binding.ivSearch.setOnClickListener {
// debouncer.debounce {
// // 执行搜索操作
// viewModel.getSearchMemberList(
// param = binding.etUserInfo.text.toString(),
// pageNum = 1
// )
// // 隐藏键盘
// KeyboardUtils.hideKeyboard(requireActivity())
// }
// }
// binding.llBind.setOnClickListener {
// if (equipmentBoxCode.isNullOrBlank().not()) {
// showBindDialog()
// return@setOnClickListener
// }
// if (info == null || info!!.equipmentCode?.isEmpty() == true || info!!.equipmentBoxCode?.isEmpty() == true) {
// ToastUtils.showToast("传入的设备信息异常")
// return@setOnClickListener
// }
// val plateNumber = binding.etCode.text.toString()
// if (plateNumber.isEmpty()) {
// ToastUtils.showToast("请输入餐盘号")
// return@setOnClickListener
// }
// if (checkedItem == null) {
// ToastUtils.showToast("请选择要绑定的会员")
// return@setOnClickListener
// }
// if (checkedItem!!.id == null) {
// ToastUtils.showToast("选中的会员信息异常")
// return@setOnClickListener
// }
// val bindParam = BindParam(
// equipmentId = info?.equipmentId,
// equipmentCode = info?.equipmentCode,
// equipmentBoxCode = info?.equipmentBoxCode,
// faceId = checkedItem?.faceId,
// plateNumber = plateNumber
// )
// viewModel.bindPlate(bindParam) { pair ->
// updateBindState(pair)
// }
// KeyboardUtils.hideKeyboard(requireActivity())
// }
// binding.tvBack.setOnClickListener { activity?.finish() }
// }
//
// /**
// * 监听数据变化
// */
// override fun registerDataChange() {
// super.registerDataChange()
// lifecycleScope.launch {
// viewModel.searchMemberList.collect {
// adapter.updateData(it)
// }
// }
//// lifecycleScope.launch {
//// viewModel.bindStateChange.collect {
//// updateBindState(it)
//// }
//// }
// }
//
// private fun createAdapter(): GenericItemAdapter<SearchResult.Member, ItemSearchUserInfoBinding> {
// return GenericItemAdapter(
// items = emptyList(),
// bindingInflater = ItemSearchUserInfoBinding::inflate,
// bindCallback = { item, position ->
// this.tvName.text = item.name.maskName()
// this.tvPhone.text = item.phone.maskPhone()
// if (item.id != checkedItem?.id) {
// this.llRoot.setBackgroundResource(R.drawable.grid_item_bind)
// } else {
// this.llRoot.setBackgroundResource(R.drawable.grid_item_unbind)
// }
//
// this.llRoot.setOnClickListener {
// Timber.d("itemClick ${item.name}, position = $position")
// checkedItem = item
// adapter.notifyDataSetChanged()
// //TODO 调用接口查询用户是否已绑盘
// this@BindPlateFragment.equipmentBoxCode = null
// (activity as? MainActivity)?.showWaitingDialog("查询中,请稍后……")
// userViewModel.getUserInfoById(memberId = item.faceId) {
// (activity as? MainActivity)?.hideWaitingDialog()
// this@BindPlateFragment.equipmentBoxCode = it?.equipmentBoxCode
// }
// }
// }
// )
// }
//
// private var equipmentBoxCode:String? = null
//
// private fun showBindDialog() {
// UserBindRemindDialog(
// activity = requireActivity(),
// content = "您已绑定编号为${equipmentBoxCode}的柜子,请解绑后重试"
// )
// .show()
// }
//
// private fun updateBindState(pair: Pair<Boolean?, ErrorInfo>){
// if (pair.first == null) return // 解绑状态过滤
// val errorInfo = pair.second
// if (errorInfo.isSuccess()) {
// if (errorInfo.equipmentUserInfo == null) {
// ToastUtils.showToast("数据异常")
// return
// }
//// if (errorInfo.equipmentUserInfo.isOtherEquipment()) {
//// MainActivity.start(
//// requireContext(),
//// pageType = PageType.PLATE_TIP,
//// equipmentUserInfo = errorInfo.equipmentUserInfo,
//// isAdmin = true
//// )
//// } else {
// SerialApi.openPlate(
// errorInfo.equipmentUserInfo.equipmentBoxCode!!.toInt(),
// object : SerialPortManager.SendCallback {
// override fun onSuccess() {
// ToastUtils.showToast("绑定成功")
// activity?.finish()
// }
//
// override fun onFail(e: Exception?) {
// ToastUtils.showToast("绑定失败")
// }
// })
//// }
// } else {
// ToastUtils.showToast(errorInfo.msg)
// }
// }
//}
@@ -41,12 +41,14 @@ class PlateOpenFragment :
binding.tvTitle.text = "暂无餐盘信息"
binding.tvSubTitle.text = "请联系管理员"
binding.tvTitle.setTextColor(requireContext().getColor(R.color.tip_title_fail))
} else if (it.isOtherEquipment()) {
binding.ivType.setImageResource(R.drawable.ic_tip_warn)
binding.tvTitle.text = "暂无餐盘信息"
binding.tvSubTitle.text = "您的餐盘绑定在${it.equipmentName ?: " "}号柜上"
binding.tvTitle.setTextColor(requireContext().getColor(R.color.tip_title_fail))
} else {
}
// else if (it.isOtherEquipment()) {
// binding.ivType.setImageResource(R.drawable.ic_tip_warn)
// binding.tvTitle.text = "暂无餐盘信息"
// binding.tvSubTitle.text = "您的餐盘绑定在${it.equipmentName ?: " "}号柜上"
// binding.tvTitle.setTextColor(requireContext().getColor(R.color.tip_title_fail))
// }
else {
binding.ivType.setImageResource(R.drawable.ic_tip_success)
binding.tvTitle.text = "柜门开启"
binding.tvSubTitle.text = "餐盘取出后请关闭柜门"
@@ -11,7 +11,9 @@ import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.comn.SerialApi
import com.sw.plate.utils.comn.SerialPortManager
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.MyApp
import com.sw.platecabinet.R
import com.sw.platecabinet.activity.BaseActivity
import com.sw.platecabinet.activity.MainActivity
import com.sw.platecabinet.activity.PageType
import com.sw.platecabinet.adapter.GenericItemAdapter
@@ -24,6 +26,8 @@ import com.sw.platecabinet.ext.formatNumber
import com.sw.platecabinet.ext.maskName
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.utils.ListArrangementUtil
import com.sw.platecabinet.utils.PlateUtils
import com.sw.platecabinet.utils.SpTool
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -80,11 +84,23 @@ class SettingListFragment :
override fun onResume() {
super.onResume()
viewModel.getEquipmentList{
// viewModel.getEquipmentList{
// updateAdapter(it)
// }
MyApp.plateList?.let {
updateAdapter(it)
}
}
// private fun getPlateData(block: (List<EquipmentUserInfo>) -> Unit) {
// MyApp.plateList?.let {
// block(it)
// }
//// viewModel.getEquipmentList { items ->
//// block(items)
//// }
// }
private fun createItemAdapter(): GenericItemAdapter<EquipmentUserInfo, ItemBindViewBinding> {
return GenericItemAdapter(
items = emptyList(),
@@ -110,7 +126,7 @@ class SettingListFragment :
item: EquipmentUserInfo,
position: Int
) {
if (item.isPlaceholder() == true) {
if (item.isPlaceholder()) {
this.llRoot.isVisible = false
return
}
@@ -133,7 +149,9 @@ class SettingListFragment :
this.llBindInfo.visibility = View.VISIBLE
this.tvUnbind.visibility = View.GONE
this.tvName.text = item.name.maskName()
// this.tvName.text = item.name.maskName()
this.tvName.text = item.plateNumber
this.tvLastTime.text = DateTimeUtils.getTimeAgo(date)
} else {
this.llRoot.setBackgroundResource(R.drawable.grid_item_unbind)
@@ -143,45 +161,25 @@ class SettingListFragment :
this.llBindInfo.visibility = View.GONE
this.tvUnbind.visibility = View.VISIBLE
}
this.llRoot.setOnClickListener {
Timber.d("itemClick llRoot ${item.name}, position = $position")
if (item.isBound()) {
MainActivity.start(
requireContext(),
pageType = PageType.UNBIND_PLATE,
equipmentUserInfo = item
)
} else {
MainActivity.start(
requireContext(),
pageType = PageType.BIND_PLATE,
equipmentUserInfo = item
)
}
}
// this.llRoot.setOnClickListener {
//// Timber.d("itemClick llRoot ${item.name}, position = $position")
// if (item.isBound()) {
// MainActivity.start(
// requireContext(),
// pageType = PageType.UNBIND_PLATE,
// equipmentUserInfo = item
// )
// } else {
// MainActivity.start(
// requireContext(),
// pageType = PageType.BIND_PLATE,
// equipmentUserInfo = item
// )
// }
// }
this.llOpen.setOnClickListener {
Timber.d("itemClick llOpen equipmentBoxCode = ${item.equipmentBoxCode}")
val equipmentBoxCode: Int = item.equipmentBoxCode?.toInt() ?: -1
if (equipmentBoxCode < 0) {
ToastUtils.showToast("餐盘柜编号错误")
return@setOnClickListener
}
showWaitingDialog("请稍等")
SerialApi.openPlate(equipmentBoxCode, object : SerialPortManager.SendCallback {
override fun onSuccess() {
hideWaitingDialog()
MainActivity.start(
requireContext(),
pageType = PageType.PLATE_TIP,
isAdmin = true
)
}
override fun onFail(e: Exception?) {
hideWaitingDialog()
ToastUtils.showToast("柜门打开失败")
}
})
// item.faceId = null
PlateUtils.open(requireActivity(), item.equipmentBoxCode)
}
}
@@ -1,95 +1,95 @@
package com.sw.platecabinet.fragment
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.lifecycleScope
import com.sw.inbound.utils.DateTimeUtils
import com.sw.plate.utils.ToastUtils
import com.sw.platecabinet.GlobalKey
import com.sw.platecabinet.activity.UnBindDialogActivity
import com.sw.platecabinet.databinding.FragmentUnbindPlateBinding
import com.sw.platecabinet.ext.maskName
import com.sw.platecabinet.ext.maskPhone
import com.sw.platecabinet.model.ErrorInfo
import com.sw.platecabinet.model.response.EquipmentUserInfo
import kotlinx.coroutines.launch
/**
* 餐盘柜绑定
*/
class UnBindPlateFragment private constructor() : BaseFragment<FragmentUnbindPlateBinding>(
FragmentUnbindPlateBinding::inflate
) {
internal val ARG_PARAM1 = "param1"
private var info: EquipmentUserInfo? = null
companion object {
@JvmStatic
fun newInstance(param1: EquipmentUserInfo?) =
UnBindPlateFragment().apply {
arguments = Bundle().apply {
putParcelable(ARG_PARAM1, param1)
}
}
}
private val dialogLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
viewModel.unbindPlate(info?.id) { pair ->
updateBindState(pair)
}
}
}
override fun initialize() {
arguments?.let { args ->
info = args.getParcelable(ARG_PARAM1)
info?.let {
binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}"
binding.tvPlateNumberValue.text = it.plateNumber
binding.tvNameValue.text = it.name.maskName()
binding.tvPhoneValue.text = it.phone.maskPhone()
val timeInfo = DateTimeUtils.parseDateTime(it.updateTime)
val timeAgo = DateTimeUtils.getTimeAgo(timeInfo)
binding.tvUpdateTimeValue.text = timeAgo
}
}
binding.llUnbind.setOnClickListener {
if (info == null) return@setOnClickListener
val intent = Intent(requireContext(), UnBindDialogActivity::class.java).apply {
putExtra(GlobalKey.PARAM_EQUIPMENT_INFO, info)
}
dialogLauncher.launch(intent)
requireActivity().overridePendingTransition(0, 0)
}
binding.tvBack.setOnClickListener {
activity?.finish()
}
}
override fun registerDataChange() {
super.registerDataChange()
// lifecycleScope.launch {
// viewModel.bindStateChange.collect {
// updateBindState(it)
//package com.sw.platecabinet.fragment
//
//import android.app.Activity
//import android.content.Intent
//import android.os.Bundle
//import androidx.activity.result.contract.ActivityResultContracts
//import androidx.lifecycle.lifecycleScope
//import com.sw.inbound.utils.DateTimeUtils
//import com.sw.plate.utils.ToastUtils
//import com.sw.platecabinet.GlobalKey
//import com.sw.platecabinet.activity.UnBindDialogActivity
//import com.sw.platecabinet.databinding.FragmentUnbindPlateBinding
//import com.sw.platecabinet.ext.maskName
//import com.sw.platecabinet.ext.maskPhone
//import com.sw.platecabinet.model.ErrorInfo
//import com.sw.platecabinet.model.response.EquipmentUserInfo
//import kotlinx.coroutines.launch
//
///**
// * 餐盘柜绑定
// */
//class UnBindPlateFragment private constructor() : BaseFragment<FragmentUnbindPlateBinding>(
// FragmentUnbindPlateBinding::inflate
//) {
// internal val ARG_PARAM1 = "param1"
// private var info: EquipmentUserInfo? = null
//
// companion object {
// @JvmStatic
// fun newInstance(param1: EquipmentUserInfo?) =
// UnBindPlateFragment().apply {
// arguments = Bundle().apply {
// putParcelable(ARG_PARAM1, param1)
// }
// }
// }
//
// private val dialogLauncher = registerForActivityResult(
// ActivityResultContracts.StartActivityForResult()
// ) { result ->
// if (result.resultCode == Activity.RESULT_OK) {
// viewModel.unbindPlate(info?.id) { pair ->
// updateBindState(pair)
// }
// }
}
private fun updateBindState(pair: Pair<Boolean?, ErrorInfo>){
if (pair.first == null) return // 绑定状态过滤
val errorInfo = pair.second
if (errorInfo.isSuccess()) {
ToastUtils.showToast("解绑成功")
// activity?.finish()
// 关闭宿主 Activity
requireActivity().finish()
requireActivity().overridePendingTransition(0, 0)
} else {
ToastUtils.showToast(errorInfo.msg)
}
}
}
// }
//
// override fun initialize() {
// arguments?.let { args ->
// info = args.getParcelable(ARG_PARAM1)
// info?.let {
// binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}"
// binding.tvPlateNumberValue.text = it.plateNumber
// binding.tvNameValue.text = it.name.maskName()
// binding.tvPhoneValue.text = it.phone.maskPhone()
// val timeInfo = DateTimeUtils.parseDateTime(it.updateTime)
// val timeAgo = DateTimeUtils.getTimeAgo(timeInfo)
// binding.tvUpdateTimeValue.text = timeAgo
// }
// }
// binding.llUnbind.setOnClickListener {
// if (info == null) return@setOnClickListener
// val intent = Intent(requireContext(), UnBindDialogActivity::class.java).apply {
// putExtra(GlobalKey.PARAM_EQUIPMENT_INFO, info)
// }
// dialogLauncher.launch(intent)
// requireActivity().overridePendingTransition(0, 0)
// }
// binding.tvBack.setOnClickListener {
// activity?.finish()
// }
// }
//
// override fun registerDataChange() {
// super.registerDataChange()
//// lifecycleScope.launch {
//// viewModel.bindStateChange.collect {
//// updateBindState(it)
//// }
//// }
// }
// private fun updateBindState(pair: Pair<Boolean?, ErrorInfo>){
// if (pair.first == null) return // 绑定状态过滤
// val errorInfo = pair.second
// if (errorInfo.isSuccess()) {
// ToastUtils.showToast("解绑成功")
//// activity?.finish()
// // 关闭宿主 Activity
// requireActivity().finish()
// requireActivity().overridePendingTransition(0, 0)
// } else {
// ToastUtils.showToast(errorInfo.msg)
// }
// }
//}
@@ -11,19 +11,19 @@ import kotlinx.parcelize.Parcelize
*/
@Parcelize
data class EquipmentUserInfo(
/**
* 主键
*/
val id: Long? = 0,
/**
*
* 设备Id
*/
val equipmentId: String? = "",
/**
* 设备编号
*/
var equipmentCode: String? = "",
// /**
// * 主键
// */
// val id: Long? = 0,
// /**
// *
// * 设备Id
// */
// val equipmentId: String? = "",
// /**
// * 设备编号
// */
// var equipmentCode: String? = "",
/**
* 设备盒子编号
*/
@@ -31,60 +31,60 @@ data class EquipmentUserInfo(
/**
* 会员Id
*/
val faceId: String? = "",
var faceId: String? = "",
/**
* 餐盘编号
*/
var plateNumber: String? = "",
/**
* 设备名称
*/
val equipmentName: String? = "",
// /**
// * 设备名称
// */
// val equipmentName: String? = "",
val orderNo: String? = "",
// val orderNo: String? = "",
/**
*
* 更新时间
*/
val updateTime: String? = "",
var updateTime: String? = "",
val name: String? = "",
val phone: String? = "",
val faceUrl: String? = "",
val mealTime: String? = "",
val mealTimeInterval: String? = "",
val openTime: String? = "",
val openTimeInterval: String? = "",
val eatCount: Int? = 0,
// val name: String? = "",
// val phone: String? = "",
// val faceUrl: String? = "",
// val mealTime: String? = "",
// val mealTimeInterval: String? = "",
// val openTime: String? = "",
// val openTimeInterval: String? = "",
// val eatCount: Int? = 0,
//
// var cardBalance: Double? = 0.toDouble(),
var cardBalance: Double? = 0.toDouble(),
/**
* 用于cardBalance后续拦截判断
*/
var showBalanceNotEnoughDialog: Boolean = false,
var isIntercept: Boolean = false
// /**
// * 用于cardBalance后续拦截判断
// */
// var showBalanceNotEnoughDialog: Boolean = false,
// var isIntercept: Boolean = false
) : Parcelable {
/**
* 是否已绑定
*/
fun isBound(): Boolean {
return faceId != null
return faceId.isNullOrBlank().not()
}
/**
* 是否是其他设备
*/
fun isOtherEquipment(): Boolean {
return equipmentCode != null && equipmentCode != "" && GlobalData.globalEquipmentCode != equipmentCode
}
// /**
// * 是否是其他设备
// */
// fun isOtherEquipment(): Boolean {
// return equipmentCode != null && equipmentCode != "" && GlobalData.globalEquipmentCode != equipmentCode
// }
fun hasEquipmentBox(): Boolean {
return !TextUtils.isEmpty(equipmentBoxCode)
}
fun isPlaceholder(): Boolean {
return equipmentBoxCode == null || equipmentBoxCode == ""
return equipmentBoxCode.isNullOrBlank()
}
}
@@ -1,104 +1,104 @@
package com.sw.platecabinet.network.task
import android.content.Context
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.arcsoft.face.FaceEngine
import com.sw.inbound.utils.GsonUtils
import com.sw.plate.App
import com.sw.plate.utils.Base64
import com.sw.plate.utils.PrefUtils
import com.sw.plate.utils.arcface.FaceApi
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.plate.utils.arcface.faceserver.FaceServer
import com.sw.platecabinet.network.ApiClient
import com.sw.platecabinet.repository.RemoteRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import timber.log.Timber
class HeartBeatTask(appContext: Context, workerParams: WorkerParameters) :
CoroutineWorker(appContext, workerParams) {
companion object {
private const val TAG = "HeartBeatTask"
}
override suspend fun doWork(): Result {
return try {
// 执行后台任务逻辑
performSync()
TaskManager.startTask()
Result.success()
} catch (e: Exception) {
e.printStackTrace()
Result.retry()
}
}
private val repository: RemoteRepository by lazy {
RemoteRepository(ApiClient.apiService)
}
private val faceApi: FaceApi = FaceApi()
private suspend fun performSync() {
// withContext(Dispatchers.IO) {
// val faceUpdateTimeStamp = PrefUtils.getLong(App.getContext(), "faceUpdateTimeStamp", 0)
// if (faceUpdateTimeStamp == 0L) {
// val timestamp = System.currentTimeMillis()
// PrefUtils.setLong(App.getContext(), "faceUpdateTimeStamp", timestamp)
// }
// val resp = repository.getHeartbeatInterface(
// PrefUtils.getLong(
// App.getContext(),
// "faceUpdateTimeStamp",
// 0
// )
// )
// Timber.tag(TAG).d("performSync: ${GsonUtils.toJson(resp)}")
// val list = resp.data
// if (list.isNullOrEmpty()) {
// return@withContext
// }
// val faceServer = FaceServer.getInstance()
// val faceEngine: FaceEngine? = faceServer.faceEngine
//package com.sw.platecabinet.network.task
//
// list.forEachIndexed { index, it ->
// try {
// if (index == list.size - 1) {
// PrefUtils.setLong(
// App.getContext(),
// "faceUpdateTimeStamp",
// it.updateTimeStamp
// )
// }
// if (it.faceType == "1") {
// if (it.userId.isNullOrBlank().not()) {
// //userId非空,根据userId删除人脸数据
// faceApi.deleteByUserName(it.userId)
// faceEngine?.removeFaceFeature(it.userId.toInt())
// }
// } else if (it.faceType == "0") {
// //新增人脸数据
// val featureData = Base64.decode(it.faceFeature)
// val insertEntity = FaceEntity(it.userId, null, featureData)
// val faceId = faceApi.insert(insertEntity)
// insertEntity.faceId = faceId
//// faceServer.registerFaceFeatureInfoFromDb(insertEntity, faceEngine)
//import android.content.Context
//import android.util.Log
//import androidx.work.CoroutineWorker
//import androidx.work.WorkerParameters
//import com.arcsoft.face.FaceEngine
//import com.sw.inbound.utils.GsonUtils
//import com.sw.plate.App
//import com.sw.plate.utils.Base64
//import com.sw.plate.utils.PrefUtils
//import com.sw.plate.utils.arcface.FaceApi
//import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
//import com.sw.plate.utils.arcface.faceserver.FaceServer
//import com.sw.platecabinet.network.ApiClient
//import com.sw.platecabinet.repository.RemoteRepository
//import kotlinx.coroutines.Dispatchers
//import kotlinx.coroutines.withContext
//import org.greenrobot.eventbus.EventBus
//import timber.log.Timber
//
// EventBus.getDefault().post(insertEntity)
//// callback(insertEntity)
// }
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }
//class HeartBeatTask(appContext: Context, workerParams: WorkerParameters) :
// CoroutineWorker(appContext, workerParams) {
//
// companion object {
// private const val TAG = "HeartBeatTask"
// }
//
// override suspend fun doWork(): Result {
// return try {
// // 执行后台任务逻辑
// performSync()
//
// TaskManager.startTask()
//
// Result.success()
// } catch (e: Exception) {
// e.printStackTrace()
// Result.retry()
// }
}
}
// }
//
// private val repository: RemoteRepository by lazy {
// RemoteRepository(ApiClient.apiService)
// }
//
// private val faceApi: FaceApi = FaceApi()
//
// private suspend fun performSync() {
//// withContext(Dispatchers.IO) {
//// val faceUpdateTimeStamp = PrefUtils.getLong(App.getContext(), "faceUpdateTimeStamp", 0)
//// if (faceUpdateTimeStamp == 0L) {
//// val timestamp = System.currentTimeMillis()
//// PrefUtils.setLong(App.getContext(), "faceUpdateTimeStamp", timestamp)
//// }
//// val resp = repository.getHeartbeatInterface(
//// PrefUtils.getLong(
//// App.getContext(),
//// "faceUpdateTimeStamp",
//// 0
//// )
//// )
//// Timber.tag(TAG).d("performSync: ${GsonUtils.toJson(resp)}")
//// val list = resp.data
//// if (list.isNullOrEmpty()) {
//// return@withContext
//// }
//// val faceServer = FaceServer.getInstance()
//// val faceEngine: FaceEngine? = faceServer.faceEngine
////
//// list.forEachIndexed { index, it ->
//// try {
//// if (index == list.size - 1) {
//// PrefUtils.setLong(
//// App.getContext(),
//// "faceUpdateTimeStamp",
//// it.updateTimeStamp
//// )
//// }
//// if (it.faceType == "1") {
//// if (it.userId.isNullOrBlank().not()) {
//// //userId非空,根据userId删除人脸数据
//// faceApi.deleteByUserName(it.userId)
//// faceEngine?.removeFaceFeature(it.userId.toInt())
//// }
//// } else if (it.faceType == "0") {
//// //新增人脸数据
//// val featureData = Base64.decode(it.faceFeature)
//// val insertEntity = FaceEntity(it.userId, null, featureData)
//// val faceId = faceApi.insert(insertEntity)
//// insertEntity.faceId = faceId
////// faceServer.registerFaceFeatureInfoFromDb(insertEntity, faceEngine)
////
//// EventBus.getDefault().post(insertEntity)
////// callback(insertEntity)
//// }
//// } catch (e: Exception) {
//// e.printStackTrace()
//// }
//// }
//// }
// }
//
//}
@@ -1,40 +1,40 @@
package com.sw.platecabinet.network.task
import androidx.lifecycle.LifecycleOwner
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.sw.plate.App
import java.util.concurrent.TimeUnit
object TaskManager {
private const val TASK_NAME = "SmartPlateCabinetTask"
// private var owner: LifecycleOwner?=null
// fun setOwner(owner: LifecycleOwner) {
// this.owner = owner
//package com.sw.platecabinet.network.task
//
//import androidx.lifecycle.LifecycleOwner
//import androidx.work.ExistingWorkPolicy
//import androidx.work.OneTimeWorkRequestBuilder
//import androidx.work.WorkInfo
//import androidx.work.WorkManager
//import com.sw.plate.App
//import java.util.concurrent.TimeUnit
//
//object TaskManager {
// private const val TASK_NAME = "SmartPlateCabinetTask"
//// private var owner: LifecycleOwner?=null
//// fun setOwner(owner: LifecycleOwner) {
//// this.owner = owner
//// }
// fun startTask() {
// val nextRequest = OneTimeWorkRequestBuilder<HeartBeatTask>()
// .setInitialDelay(1, TimeUnit.MINUTES)
//// .setInputData(inputData)
// .build()
// WorkManager.getInstance(App.getContext())
//// .apply{
//// getWorkInfoByIdLiveData(nextRequest.id)
//// .observe(owner) { workInfo ->
//// if (workInfo?.state == WorkInfo.State.SUCCEEDED) {
//// val result = workInfo.outputData.getString("RESULT_KEY")
//// // 使用返回的结果
//// }
//// }
//// }
// .enqueueUniqueWork(TASK_NAME, ExistingWorkPolicy.REPLACE, nextRequest)
// }
fun startTask() {
val nextRequest = OneTimeWorkRequestBuilder<HeartBeatTask>()
.setInitialDelay(1, TimeUnit.MINUTES)
// .setInputData(inputData)
.build()
WorkManager.getInstance(App.getContext())
// .apply{
// getWorkInfoByIdLiveData(nextRequest.id)
// .observe(owner) { workInfo ->
// if (workInfo?.state == WorkInfo.State.SUCCEEDED) {
// val result = workInfo.outputData.getString("RESULT_KEY")
// // 使用返回的结果
// }
// }
// }
.enqueueUniqueWork(TASK_NAME, ExistingWorkPolicy.REPLACE, nextRequest)
}
fun cancelTask() {
WorkManager.getInstance(App.getContext())
.cancelUniqueWork(TASK_NAME)
}
}
//
// fun cancelTask() {
// WorkManager.getInstance(App.getContext())
// .cancelUniqueWork(TASK_NAME)
// }
//
//}
@@ -0,0 +1,33 @@
package com.sw.platecabinet.utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlin.ranges.downTo
// 倒计时Flow扩展函数
fun countDownByFlow(
total: Int,
scope: CoroutineScope,
onTick: (Int) -> Unit,
onStart: (() -> Unit)? = null,
onFinish: (() -> Unit)? = null
): Job {
return flow {
for (i in total downTo 0) {
emit(i)
if (i != 0) delay(1000)
}
}.flowOn(Dispatchers.Main)
.onStart { onStart?.invoke() }
.onCompletion { onFinish?.invoke() }
.onEach { onTick.invoke(it) }
.launchIn(scope)
}
@@ -0,0 +1,41 @@
package com.sw.platecabinet.utils
import androidx.fragment.app.FragmentActivity
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.comn.SerialApi
import com.sw.plate.utils.comn.SerialPortManager
import com.sw.platecabinet.activity.BaseActivity
import com.sw.platecabinet.activity.MainActivity
import com.sw.platecabinet.activity.PageType
import timber.log.Timber
object PlateUtils {
fun open(fragmentActivity: FragmentActivity, code: String?) {
val activity = fragmentActivity as BaseActivity<*>
Timber.d("itemClick llOpen equipmentBoxCode = ${code}")
val equipmentBoxCode: Int = code?.toInt() ?: -1
if (equipmentBoxCode < 0) {
ToastUtils.showToast("餐盘柜编号错误")
return
}
activity.showWaitingDialog("请稍等")
SerialApi.openPlate(equipmentBoxCode, object : SerialPortManager.SendCallback {
override fun onSuccess() {
activity.hideWaitingDialog()
MainActivity.start(
activity,
pageType = PageType.PLATE_TIP,
isAdmin = true
)
}
override fun onFail(e: Exception?) {
activity.hideWaitingDialog()
ToastUtils.showToast("柜门打开失败")
}
})
}
}
@@ -1,20 +1,42 @@
package com.sw.platecabinet.utils;
package com.sw.platecabinet.utils
import com.sw.inbound.utils.SPUtil;
import com.sw.platecabinet.MyApp;
import com.google.gson.Gson
import com.sw.inbound.utils.GsonUtils
import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.SPUtil.Companion.getInstance
import com.sw.platecabinet.MyApp
import com.sw.platecabinet.model.response.EquipmentUserInfo
public class SpTool {
object SpTool {
const val LAST_FACE_TIMESTAMP: String = "faceTimestamp"
const val PLATE_BOX_DATA: String = "plateBoxBind"
private var spUtil: SPUtil? = null
public static final String LAST_FACE_TIMESTAMP = "faceTimestamp";
public static long getLastFaceTimestamp() {
return SPUtil.Companion.getInstance(MyApp.getContext(), "default_sp").get(LAST_FACE_TIMESTAMP, 0L);
init {
spUtil = getInstance(MyApp.instance!!, "default_sp")
}
public static void setLastFaceTimestamp(long timestamp) {
SPUtil.Companion.getInstance(MyApp.getContext(), "default_sp").put(LAST_FACE_TIMESTAMP, timestamp);
fun putString(key:String, value:String) {
spUtil?.put(key, value)
}
var lastFaceTimestamp: Long
get() = spUtil?.get<Long?>(SpTool.LAST_FACE_TIMESTAMP, 0L) ?: 0
set(timestamp) {
spUtil?.put(LAST_FACE_TIMESTAMP, timestamp)
}
fun savePlateData(items: List<EquipmentUserInfo>) {
val jsonData = Gson().toJson(items)
putString(PLATE_BOX_DATA, jsonData)
}
fun getPlateData(): List<EquipmentUserInfo>? {
val jsonData = spUtil?.get(PLATE_BOX_DATA, "")
if (jsonData.isNullOrBlank()) {
return null
}
return GsonUtils.fromJsonList(jsonData, EquipmentUserInfo::class.java)
}
}
@@ -61,15 +61,15 @@ class SettingViewModel : BaseViewModel() {
//// }
//// _equipmentList.value = list
// }
fun getEquipmentList(block: (List<EquipmentUserInfo>) -> Unit) {
launchWithLoading {
val response = repository.getEquipmentList()
if (parseResponse(response)) {
val list = response.data ?: emptyList()
block(list)
}
}
}
// fun getEquipmentList(block: (List<EquipmentUserInfo>) -> Unit) {
// launchWithLoading {
// val response = repository.getEquipmentList()
// if (parseResponse(response)) {
// val list = response.data ?: emptyList()
// block(list)
// }
// }
// }
/**
* 搜索会员信息列表
@@ -172,19 +172,19 @@ class SettingViewModel : BaseViewModel() {
fun bindPlate(bindParam: BindParam, block:(Pair<Boolean?, ErrorInfo>)-> Unit) {
launchWithLoading {
val response = repository.plateBind(bindParam)
if (parseResponse(response)) {
var userInfo = response.data
if (userInfo == null) {
userInfo = EquipmentUserInfo()
userInfo.equipmentBoxCode = bindParam.equipmentBoxCode
userInfo.plateNumber = bindParam.plateNumber
userInfo.equipmentCode = bindParam.equipmentCode
}
block(true to ErrorInfo(equipmentUserInfo = userInfo))
} else {
block(true to ErrorInfo(response.code, response.msg.toString()))
}
// val response = repository.plateBind(bindParam)
// if (parseResponse(response)) {
// var userInfo = response.data
// if (userInfo == null) {
// userInfo = EquipmentUserInfo()
// userInfo.equipmentBoxCode = bindParam.equipmentBoxCode
// userInfo.plateNumber = bindParam.plateNumber
// userInfo.equipmentCode = bindParam.equipmentCode
// }
// block(true to ErrorInfo(equipmentUserInfo = userInfo))
// } else {
// block(true to ErrorInfo(response.code, response.msg.toString()))
// }
}
}
@@ -192,20 +192,20 @@ class SettingViewModel : BaseViewModel() {
plateNumber: String,
equipmentCode: String = globalEquipmentCode
) {
_searchUserInfo.value = null
launchWithLoading {
// val bindParam = BindParam(plateNumber = plateNumber)
val response = repository.findByPlateNumber(plateNumber)
if (response.code == "00000") {
_searchUserInfo.value = response.data
} else {
_searchUserInfo.value = EquipmentUserInfo(
plateNumber = plateNumber,
equipmentCode = equipmentCode,
updateTime = DateTimeUtils.getDateTimeString()
)
}
}
// _searchUserInfo.value = null
// launchWithLoading {
//// val bindParam = BindParam(plateNumber = plateNumber)
// val response = repository.findByPlateNumber(plateNumber)
// if (response.code == "00000") {
// _searchUserInfo.value = response.data
// } else {
// _searchUserInfo.value = EquipmentUserInfo(
// plateNumber = plateNumber,
// equipmentCode = equipmentCode,
// updateTime = DateTimeUtils.getDateTimeString()
// )
// }
// }
}
val PAGE_SIZE = 100
@@ -83,7 +83,7 @@ class UserViewModel : BaseViewModel() {
if (list.isNotEmpty()) {
faceTimestamp = list.last().faceUpdateTimestamp?:0
}
SpTool.setLastFaceTimestamp(faceTimestamp)
SpTool.lastFaceTimestamp = faceTimestamp
//activeEngine()
}
}