添加init界面,调整了认证后逻辑,调整了扫描枪扫描处理
This commit is contained in:
@@ -26,6 +26,9 @@ object GlobalData {
|
||||
*/
|
||||
var arrayMode: Int = 0
|
||||
|
||||
var appId = "Hkz1rBk6PZXbS8KwKr67K2eZtsz8bRoMHLg64bUdgCZj"
|
||||
var sdkKey = "AabXs3sHM8UhhE7oCGf4LVMLrdkGb1nJNksbjjTdVt7k"
|
||||
var activeKey = "085F-118G-Q391-53YL"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -318,7 +318,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
}
|
||||
if (equipmentUserInfo.equipmentBoxCode?.isNotEmpty() == true) {
|
||||
SerialApi.openPlate(
|
||||
equipmentUserInfo.equipmentBoxCode.toInt(),
|
||||
equipmentUserInfo.equipmentBoxCode!!.toInt(),
|
||||
object : SerialPortManager.SendCallback {
|
||||
override fun onSuccess() {
|
||||
MainActivity.start(context, pageType = PageType.PLATE_TIP)
|
||||
@@ -343,6 +343,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
SerialApi.close()
|
||||
timeJob?.cancel()
|
||||
keyEventHelper?.onDestroy()
|
||||
super.onDestroy()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.sw.platecabinet.activity
|
||||
|
||||
import android.content.Intent
|
||||
import com.sw.platecabinet.databinding.ActivityInitBinding
|
||||
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||
|
||||
class InitActivity : BaseActivity<ActivityInitBinding>() {
|
||||
override fun inflateViewBinding(): ActivityInitBinding {
|
||||
return ActivityInitBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
override fun inflateTitleBinding(): ItemTitleTimeBinding? {
|
||||
return binding.includeHeader
|
||||
}
|
||||
|
||||
override fun initialize() {
|
||||
binding.main.setOnClickListener {
|
||||
val intent = Intent(this, LoginByFaceActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onLeftDoubleClick() {
|
||||
finish()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.graphics.Point
|
||||
import android.hardware.Camera
|
||||
import android.os.Build
|
||||
import android.os.CountDownTimer
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -29,8 +30,8 @@ import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
|
||||
import com.sw.platecabinet.R
|
||||
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
|
||||
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||
import com.sw.platecabinet.model.response.EquipmentUserInfo
|
||||
import com.sw.platecabinet.utils.PermissionHelper
|
||||
import com.sw.platecabinet.utils.ThreadUtils
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
@@ -39,6 +40,7 @@ import timber.log.Timber
|
||||
class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
private val recognizeViewModel by viewModels<RecognizeViewModel>()
|
||||
private var countDownTimer: CountDownTimer? = null
|
||||
|
||||
private val CAMERA_PERMISSION_REQUEST_CODE = 100
|
||||
private val REQUIRED_PERMISSIONS: Array<String> = arrayOf(
|
||||
@@ -55,11 +57,19 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
return binding.includeHeader
|
||||
}
|
||||
|
||||
override fun initialize() {
|
||||
ThreadUtils.launch {
|
||||
viewModel.activeEngine()
|
||||
}
|
||||
companion object {
|
||||
private var instance: LoginByFaceActivity? = null
|
||||
|
||||
fun finishActivity() {
|
||||
instance?.finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun initialize() {
|
||||
instance = this
|
||||
viewModel.activeEngine()
|
||||
|
||||
initCountTime()
|
||||
initArcViewModel()
|
||||
initArcView()
|
||||
openRectInfoDraw = true
|
||||
@@ -157,6 +167,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
instance = null
|
||||
if (rgbCameraHelper != null) {
|
||||
rgbCameraHelper!!.release()
|
||||
rgbCameraHelper = null
|
||||
@@ -356,6 +367,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
super.onResume()
|
||||
resumeCamera()
|
||||
viewModel.resetUserInfo()
|
||||
countDownTimer?.let {
|
||||
it.cancel()
|
||||
it.start()
|
||||
}
|
||||
}
|
||||
|
||||
protected override fun onPause() {
|
||||
@@ -369,4 +384,21 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
||||
recognizeViewModel.onPreviewFrame(ByteArray(1382400), true)
|
||||
}
|
||||
|
||||
override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
|
||||
super.handleLoginSuccess(equipmentUserInfo, isAdmin)
|
||||
finish()
|
||||
}
|
||||
|
||||
fun initCountTime() {
|
||||
val totalTimeInMillis = 30L * 1000
|
||||
countDownTimer = object : CountDownTimer(totalTimeInMillis, 1000) {
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
binding.tvToInit.text = "${(millisUntilFinished / 1000).toInt() + 1}"
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
finish()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
|
||||
|
||||
override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
|
||||
super.handleLoginSuccess(equipmentUserInfo, isAdmin)
|
||||
LoginByFaceActivity.finishActivity()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
package com.sw.platecabinet.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.text.TextUtils
|
||||
import android.text.TextWatcher
|
||||
import android.view.inputmethod.EditorInfo
|
||||
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
|
||||
@@ -23,6 +24,7 @@ import com.sw.platecabinet.ext.maskName
|
||||
import com.sw.platecabinet.ext.maskPhone
|
||||
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 kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -39,6 +41,7 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
|
||||
private var info: EquipmentUserInfo? = null
|
||||
private var checkedItem: SearchResult.Member? = null
|
||||
private var lastText = ""
|
||||
private val debouncer = Debouncer(2000)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@@ -94,21 +97,25 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
|
||||
}
|
||||
})
|
||||
(activity as MainActivity).registerKeyEventInfo {
|
||||
binding.etCode.text = Editable.Factory.getInstance().newEditable(it)
|
||||
if (binding.etUserInfo.isFocused) return@registerKeyEventInfo
|
||||
binding.etCode.text.clear()
|
||||
binding.etCode.postDelayed({
|
||||
binding.etCode.text.clear()
|
||||
binding.etCode.text = Editable.Factory.getInstance().newEditable(it)
|
||||
binding.etUserInfo.requestFocus()
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initListener() {
|
||||
binding.etUserInfo.addTextChangedListener(object : TextWatcher {
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val debounceDelay = 500L // 延迟 500 毫秒
|
||||
|
||||
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(
|
||||
@@ -117,20 +124,32 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
|
||||
before: Int,
|
||||
count: Int
|
||||
) {
|
||||
Timber.d("onTextChanged s = ${s.toString()}, start = $start, count = $count, before = $before")
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val currentText = s.toString()
|
||||
if (currentText == lastText) return // 内容未变化时不处理
|
||||
lastText = currentText
|
||||
handler.removeCallbacksAndMessages(null) // 取消之前的延迟任务
|
||||
handler.postDelayed({
|
||||
// if (currentText.isNotEmpty()) {
|
||||
viewModel.getSearchMemberList(param = currentText, pageNum = 1)
|
||||
// }
|
||||
}, debounceDelay)
|
||||
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.llBind.setOnClickListener {
|
||||
if (info == null || info!!.equipmentCode?.isEmpty() == true || info!!.equipmentBoxCode?.isEmpty() == true) {
|
||||
ToastUtils.showToast("传入的设备信息异常")
|
||||
@@ -176,15 +195,29 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
|
||||
if (it.first == null) return@collect // 解绑状态过滤
|
||||
val errorInfo = it.second
|
||||
if (errorInfo.isSuccess()) {
|
||||
if (errorInfo.equipmentUserInfo?.isOtherEquipment() == true) {
|
||||
if (errorInfo.equipmentUserInfo == null) {
|
||||
ToastUtils.showToast("数据异常")
|
||||
return@collect
|
||||
}
|
||||
if (errorInfo.equipmentUserInfo.isOtherEquipment() == true) {
|
||||
MainActivity.start(
|
||||
requireContext(),
|
||||
pageType = PageType.PLATE_TIP,
|
||||
equipmentUserInfo = errorInfo.equipmentUserInfo
|
||||
)
|
||||
} else {
|
||||
ToastUtils.showToast("绑定成功")
|
||||
activity?.finish()
|
||||
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)
|
||||
|
||||
@@ -15,12 +15,12 @@ data class EquipmentUserInfo(
|
||||
* 设备盒子编号
|
||||
*/
|
||||
@SerializedName("equipmentBoxCode")
|
||||
val equipmentBoxCode: String? = "",
|
||||
var equipmentBoxCode: String? = "",
|
||||
/**
|
||||
* 设备编号
|
||||
*/
|
||||
@SerializedName("equipmentCode")
|
||||
val equipmentCode: String? = "",
|
||||
var equipmentCode: String? = "",
|
||||
/**
|
||||
*
|
||||
* 设备Id
|
||||
@@ -71,7 +71,7 @@ data class EquipmentUserInfo(
|
||||
* 是否是其他设备
|
||||
*/
|
||||
fun isOtherEquipment(): Boolean {
|
||||
return GlobalData.globalEquipmentCode != equipmentCode
|
||||
return equipmentCode != null && equipmentCode != "" && GlobalData.globalEquipmentCode != equipmentCode
|
||||
}
|
||||
|
||||
fun isPlaceholder(): Boolean {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.sw.platecabinet.utils
|
||||
|
||||
class Debouncer(private val delayMillis: Long) {
|
||||
private var lastActionTime = 0L
|
||||
|
||||
/**
|
||||
* 执行防抖操作
|
||||
* @param action 要执行的操作
|
||||
* @return Boolean 是否执行了操作 (true=已执行, false=被防抖)
|
||||
*/
|
||||
fun debounce(action: () -> Unit): Boolean {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (currentTime - lastActionTime >= delayMillis) {
|
||||
lastActionTime = currentTime
|
||||
action()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 重置防抖计时
|
||||
fun reset() {
|
||||
lastActionTime = 0L
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package com.sw.platecabinet.utils
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* 多功能线程工具类
|
||||
* 结合协程、Handler和线程池实现线程切换
|
||||
*/
|
||||
object ThreadUtils : CoroutineScope {
|
||||
// 主线程Handler
|
||||
private val mainHandler by lazy { Handler(Looper.getMainLooper()) }
|
||||
|
||||
// 后台线程池(IO密集型任务)
|
||||
private val ioThreadPool: ExecutorService by lazy {
|
||||
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2)
|
||||
}
|
||||
|
||||
// CPU密集型线程池
|
||||
private val cpuThreadPool: ExecutorService by lazy {
|
||||
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
|
||||
}
|
||||
|
||||
// 协程Job管理
|
||||
private val job = Job()
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
|
||||
// ========== Handler相关方法 ==========
|
||||
|
||||
/**
|
||||
* 在主线程执行任务
|
||||
* @param delayMillis 延迟时间(毫秒)
|
||||
*/
|
||||
fun runOnUiThread(delayMillis: Long = 0, block: () -> Unit) {
|
||||
if (delayMillis > 0) {
|
||||
mainHandler.postDelayed(block, delayMillis)
|
||||
} else {
|
||||
if (isOnMainThread()) {
|
||||
block()
|
||||
} else {
|
||||
mainHandler.post(block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除主线程任务
|
||||
*/
|
||||
fun removeUiThreadTask(block: () -> Unit) {
|
||||
mainHandler.removeCallbacks(block)
|
||||
}
|
||||
|
||||
// ========== 线程池相关方法 ==========
|
||||
|
||||
/**
|
||||
* 在IO线程执行任务
|
||||
*/
|
||||
fun runOnIoThread(block: () -> Unit) {
|
||||
ioThreadPool.execute(block)
|
||||
}
|
||||
|
||||
/**
|
||||
* 在CPU计算线程执行任务
|
||||
*/
|
||||
fun runOnCpuThread(block: () -> Unit) {
|
||||
cpuThreadPool.execute(block)
|
||||
}
|
||||
|
||||
// ========== 协程相关方法 ==========
|
||||
|
||||
/**
|
||||
* 启动协程(默认在主线程)
|
||||
*/
|
||||
fun launch(block: suspend CoroutineScope.() -> Unit): Job {
|
||||
return launch(coroutineContext, block = block)
|
||||
}
|
||||
|
||||
/**
|
||||
* 在IO线程启动协程
|
||||
*/
|
||||
fun launchOnIo(block: suspend CoroutineScope.() -> Unit): Job {
|
||||
return launch(Dispatchers.IO, block = block)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换到主线程(协程环境)
|
||||
*/
|
||||
suspend fun <T> switchToMain(block: suspend CoroutineScope.() -> T): T {
|
||||
return withContext(Dispatchers.Main, block)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换到IO线程(协程环境)
|
||||
*/
|
||||
suspend fun <T> switchToIo(block: suspend CoroutineScope.() -> T): T {
|
||||
return withContext(Dispatchers.IO, block)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在主线程
|
||||
*/
|
||||
fun isOnMainThread(): Boolean {
|
||||
return Looper.myLooper() == Looper.getMainLooper()
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放资源
|
||||
*/
|
||||
fun release() {
|
||||
job.cancel()
|
||||
ioThreadPool.shutdown()
|
||||
cpuThreadPool.shutdown()
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,13 @@ class SettingViewModel : BaseViewModel() {
|
||||
)
|
||||
val response = repository.bindEquipment(bindParam)
|
||||
if (parseResponse(response)) {
|
||||
val userInfo = response.data
|
||||
var userInfo = response.data
|
||||
if (userInfo == null) {
|
||||
userInfo = EquipmentUserInfo()
|
||||
userInfo.equipmentBoxCode = equipmentBoxCode
|
||||
userInfo.plateNumber = plateNumber
|
||||
userInfo.equipmentCode = equipmentCode
|
||||
}
|
||||
_bindStateChange.value = true to ErrorInfo(equipmentUserInfo = userInfo)
|
||||
} else {
|
||||
_bindStateChange.value = true to ErrorInfo(response.code, response.msg.toString())
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.sw.platecabinet.viewmodel
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.arcsoft.face.ErrorInfo
|
||||
import com.sw.inbound.utils.SPUtil
|
||||
import com.sw.plate.App
|
||||
@@ -13,10 +14,10 @@ import com.sw.platecabinet.GlobalKey
|
||||
import com.sw.platecabinet.model.request.LoginParam
|
||||
import com.sw.platecabinet.model.response.EquipmentUserInfo
|
||||
import com.sw.platecabinet.model.response.UserFaceModel
|
||||
import com.sw.platecabinet.utils.ThreadUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
@@ -70,18 +71,17 @@ class UserViewModel : BaseViewModel() {
|
||||
*/
|
||||
fun activeEngine() {
|
||||
Timber.d("activeEngine")
|
||||
var appId = "Hkz1rBk6PZXbS8KwKr67K2eZtsz8bRoMHLg64bUdgCZj"
|
||||
var sdkKey = "AabXs3sHM8UhhE7oCGf4LVMLrdkGb1nJNksbjjTdVt7k"
|
||||
var activeKey = "085F-118G-Q391-53YL"
|
||||
|
||||
faceApi.activeEngine(
|
||||
App.getContext(),
|
||||
appId,
|
||||
sdkKey,
|
||||
activeKey,
|
||||
GlobalData.appId,
|
||||
GlobalData.sdkKey,
|
||||
GlobalData.activeKey,
|
||||
object : FaceApi.ActiveCallback {
|
||||
override fun onSuccess(activeCode: Int) {
|
||||
Timber.d("activeEngine activeCode = $activeCode")
|
||||
ThreadUtils.launch {
|
||||
// ThreadUtils.launch {
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
when (activeCode) {
|
||||
ErrorInfo.MOK -> {
|
||||
ToastUtils.showToast("激活引擎成功")
|
||||
@@ -99,7 +99,7 @@ class UserViewModel : BaseViewModel() {
|
||||
}
|
||||
|
||||
override fun onFail(e: Exception?) {
|
||||
ThreadUtils.launch {
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
ToastUtils.showToast("激活引擎异常,${e?.message}")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user