20 Commits
Author SHA1 Message Date
马增飞 582be4e9b7 绑定解绑功能调试;其它优化 2026-01-05 18:38:10 +08:00
马增飞 17d47a876f 增加配置接口;调试人脸识别;验证手机号密码登录和人脸登录功能; 2025-12-29 18:41:48 +08:00
马增飞 6c28260069 Merge remote-tracking branch 'refs/remotes/origin/main_新版_lvmeng_1222' into main_新版_lvmeng_1229 2025-12-29 09:57:05 +08:00
马增飞 7097bbf907 优化 2025-12-29 09:55:49 +08:00
lvmeng c046441d4e 优化 2025-12-26 14:16:01 +08:00
lvmeng 7a6c4012d1 餐盘柜接口改造 2025-12-26 14:05:41 +08:00
mazengfei 5e4dc4baa4 处理人脸数据不同步 2025-11-07 20:37:50 +08:00
mazengfei 4231c68cdc 添加方法 2025-11-07 15:18:15 +08:00
mazengfei 55ba11bf34 修改人脸同步逻辑 2025-11-07 10:55:48 +08:00
马增飞 abe594fb66 设备联调 2025-11-06 19:34:42 +08:00
lvmeng fb074c1aaa 修改开机初始化页面 2025-09-26 16:11:00 +08:00
lvmeng 73456046c5 增加初始化页面 2025-09-17 17:42:38 +08:00
lvmeng 7f56d4d1a1 修改待机也按钮名称 2025-09-17 15:45:00 +08:00
lvmeng 1658b6fe6f logo修改 2025-09-12 13:32:10 +08:00
lvmeng e9a366b52a 增加心跳处理人脸数据增减 2025-09-09 15:59:29 +08:00
lvmeng 3b492cb710 待机页面优化 2025-09-05 17:59:30 +08:00
lvmeng eaafeab1d8 增加余额不足判断 2025-09-05 15:29:43 +08:00
zxj 578a9aaced 添加注释 2025-08-22 16:28:20 +08:00
zxj cd375bfaf8 修复了登录成功后跳转界面错误问题 2025-08-21 15:50:05 +08:00
zxj 7a832ec40d 调整了初始化界面逻辑 2025-08-14 13:36:45 +08:00
71 changed files with 2094 additions and 468 deletions
Generated
+1
View File
@@ -0,0 +1 @@
SmartPlateCabinet
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>
+3 -6
View File
@@ -2,20 +2,17 @@
<project version="4"> <project version="4">
<component name="deploymentTargetSelector"> <component name="deploymentTargetSelector">
<selectionStates> <selectionStates>
<SelectionState runConfigName="SmartPlateCabinet.app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-07-25T08:39:03.160022800Z"> <DropdownSelection timestamp="2025-11-06T09:21:30.965681400Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="Default" identifier="serial=?;connection=93a2ccce" /> <DeviceId pluginId="Default" identifier="serial=?;connection=3c39678a" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>
<DialogSelection /> <DialogSelection />
</SelectionState> </SelectionState>
<SelectionState runConfigName="LoginByFaceActivity">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates> </selectionStates>
</component> </component>
</project> </project>
+1 -1
View File
@@ -6,7 +6,7 @@
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" /> <option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="17" /> <option name="gradleJvm" value="azul-17" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
+1 -2
View File
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="zulu-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">
+12 -5
View File
@@ -22,14 +22,14 @@ android {
minSdk = 24 minSdk = 24
targetSdk = 35 targetSdk = 35
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// ndk { ndk {
// abiFilters.addAll(listOf("armeabi-v7a"/*, "arm64-v8a"*/)) abiFilters.addAll(listOf("armeabi-v7a"/*, "arm64-v8a"*/))
// } }
setProperty("archivesBaseName", "智能餐盘柜_${versionName}") setProperty("archivesBaseName", "zncpg_${versionName}")
} }
buildTypes { buildTypes {
@@ -93,4 +93,11 @@ dependencies {
implementation(libs.androidx.activity.ktx) implementation(libs.androidx.activity.ktx)
implementation(libs.androidx.fragment.ktx) implementation(libs.androidx.fragment.ktx)
// implementation(libs.adapter.coroutines) // implementation(libs.adapter.coroutines)
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation(libs.core)
implementation(libs.android.core)
implementation("org.greenrobot:eventbus:3.3.1")
} }
+30 -14
View File
@@ -14,41 +14,57 @@
<uses-permission <uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application <application
android:name=".MyApp" android:name=".MyApp"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_logo512"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_logo512"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.SmartPlateCabinet" android:theme="@style/Theme.SmartPlateCabinet"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="true"
tools:targetApi="31"> tools:targetApi="31">
<!-- 注册BootReceiver,监听开机完成广播 -->
<receiver
android:name=".receiver.BootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity <activity
android:name=".activity.UnBindDialogActivity" android:name=".activity.UnBindDialogActivity"
android:exported="false" android:exported="false"
android:theme="@style/DialogActivityTheme" /> android:theme="@style/DialogActivity" />
<activity <activity
android:name=".activity.InitActivity" android:name=".activity.InitActivity"
android:exported="true"> android:exported="false"
android:launchMode="singleTask">
</activity>
<activity
android:name=".activity.LoginByPwdActivity"
android:exported="false"
android:launchMode="singleTask"/>
<activity
android:name=".activity.LoginByFaceActivity"
android:exported="true"
android:launchMode="singleTask"/>
<activity
android:name=".activity.DeviceInitActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".activity.LoginByPwdActivity"
android:exported="false"
android:launchMode="singleTask">
</activity>
<activity
android:name=".activity.LoginByFaceActivity"
android:exported="false"
android:launchMode="singleTask">
</activity>
<activity <activity
android:name=".activity.MainActivity" android:name=".activity.MainActivity"
android:exported="false"> android:exported="false">
@@ -28,7 +28,18 @@ object GlobalData {
var appId = "Hkz1rBk6PZXbS8KwKr67K2eZtsz8bRoMHLg64bUdgCZj" var appId = "Hkz1rBk6PZXbS8KwKr67K2eZtsz8bRoMHLg64bUdgCZj"
var sdkKey = "AabXs3sHM8UhhE7oCGf4LVMLrdkGb1nJNksbjjTdVt7k" var sdkKey = "AabXs3sHM8UhhE7oCGf4LVMLrdkGb1nJNksbjjTdVt7k"
var activeKey = "085F-118G-Q391-53YL" var activeKey ="085F-118G-Q3J6-35UX" //"085F-118G-Q391-53YL"
/**
* 具体业务baseurl
*/
var appBaseUrl: String = "https://dev.yixiong-tech.com:8081"
/**
* 设备id
*/
var deviceId: String = ""
var restId: String = ""
} }
/** /**
@@ -45,6 +56,7 @@ object Constants {
* key * key
*/ */
object GlobalKey { object GlobalKey {
const val KEY_EQUIPMENT_INFO = "equipmentInfo"
const val KEY_TOKEN = "tokenKey" const val KEY_TOKEN = "tokenKey"
const val KEY_FIRST_RUN = "firstRun" const val KEY_FIRST_RUN = "firstRun"
const val KEY_USER_INFO = "userInfoKey" const val KEY_USER_INFO = "userInfoKey"
@@ -1,5 +1,6 @@
package com.sw.platecabinet package com.sw.platecabinet
import android.util.Log
import com.sw.plate.App import com.sw.plate.App
import com.sw.plate.utils.AppUtil import com.sw.plate.utils.AppUtil
import com.sw.platecabinet.utils.CrashHandler import com.sw.platecabinet.utils.CrashHandler
@@ -24,7 +25,14 @@ class MyApp : App() {
* 初始化全局数据 * 初始化全局数据
*/ */
private fun initGlobalData() { private fun initGlobalData() {
var deviceId = AppUtil.getUDID(this)
deviceId = "be154831-3466-3ba2-a2ea-57652c919fed"
Log.d("MyApp", "initialize: deviceId=$deviceId")
GlobalData.deviceId = deviceId
GlobalData.appVersion = AppUtil.getAppVersionCode(this).toString() GlobalData.appVersion = AppUtil.getAppVersionCode(this).toString()
GlobalData.globalEquipmentCode = "202501171634" GlobalData.globalEquipmentCode = "202501171634"
// GlobalData.appBaseUrl = "http://192.168.1.201:14801"
} }
} }
@@ -17,15 +17,23 @@ import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.sw.inbound.utils.DateTimeUtils import com.sw.inbound.utils.DateTimeUtils
import com.sw.plate.utils.Base64
import com.sw.plate.utils.ScanGunKeyEventHelper import com.sw.plate.utils.ScanGunKeyEventHelper
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.facedb.FaceDatabase
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.SerialApi
import com.sw.plate.utils.comn.SerialPortManager import com.sw.plate.utils.comn.SerialPortManager
import com.sw.platecabinet.R import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.dialog.BalanceNotEnoughDialog
import com.sw.platecabinet.ext.setClickListeners import com.sw.platecabinet.ext.setClickListeners
import com.sw.platecabinet.model.response.EquipmentUserInfo 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.PermissionHelper
import com.sw.platecabinet.utils.SpTool
import com.sw.platecabinet.view.CustomLoadingDialog import com.sw.platecabinet.view.CustomLoadingDialog
import com.sw.platecabinet.viewmodel.SettingViewModel import com.sw.platecabinet.viewmodel.SettingViewModel
import com.sw.platecabinet.viewmodel.UserViewModel import com.sw.platecabinet.viewmodel.UserViewModel
@@ -76,6 +84,8 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
registerKeyEvent() registerKeyEvent()
val durationTime = System.currentTimeMillis() - startTime val durationTime = System.currentTimeMillis() - startTime
Timber.d("启动时间:$durationTime") Timber.d("启动时间:$durationTime")
startFaceTask()
} }
/** /**
@@ -269,6 +279,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
lifecycleScope.launch { lifecycleScope.launch {
viewModel.currentUserInfo.collect { viewModel.currentUserInfo.collect {
if (it == null) return@collect if (it == null) return@collect
it.showBalanceNotEnoughDialog = true
handleLoginSuccess(it, false) handleLoginSuccess(it, false)
} }
} }
@@ -289,23 +300,27 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
handleLoginSuccess(it, true) handleLoginSuccess(it, true)
} }
} }
lifecycleScope.launch { // lifecycleScope.launch {
settingViewModel.equipmentList.collect { // settingViewModel.equipmentList.collect {
if (it.isEmpty()) return@collect // loadEquipmentList(it)
val unbindList = it.filter { !it.isBound() } // }
if (unbindList.isEmpty()) { // }
MainActivity.start(context = context, pageType = PageType.PLATE_CABINET_FULL) }
} else {
val firstInfo = unbindList[0] private fun loadEquipmentList(items: List<EquipmentUserInfo>) {
val currentUserInfo = settingViewModel.searchUserInfo.value if (items.isEmpty()) return
firstInfo.plateNumber = currentUserInfo?.plateNumber ?: "" val unbindList = items.filter { !it.isBound() }
MainActivity.start( if (unbindList.isEmpty()) {
context = context, MainActivity.start(context = context, pageType = PageType.PLATE_CABINET_FULL)
pageType = PageType.BIND_PLATE, } else {
equipmentUserInfo = firstInfo val firstInfo = unbindList[0]
) val currentUserInfo = settingViewModel.searchUserInfo.value
} firstInfo.plateNumber = currentUserInfo?.plateNumber ?: ""
} MainActivity.start(
context = context,
pageType = PageType.BIND_PLATE,
equipmentUserInfo = firstInfo
)
} }
} }
@@ -315,21 +330,35 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
*/ */
open fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) { open fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
Timber.d("handleLoginSuccess isAdmin = $isAdmin") Timber.d("handleLoginSuccess isAdmin = $isAdmin")
viewModel.resetUserInfo() equipmentUserInfo.isIntercept = false
if (equipmentUserInfo.isOtherEquipment()) { val cardBalance = equipmentUserInfo.cardBalance ?: 0.toDouble()
MainActivity.start( val balanceIsNotEnough = cardBalance <= 0.toDouble()
context, if (balanceIsNotEnough && equipmentUserInfo.showBalanceNotEnoughDialog) {
pageType = PageType.PLATE_TIP, //提示余额不足弹窗
equipmentUserInfo = equipmentUserInfo equipmentUserInfo.isIntercept = true
) BalanceNotEnoughDialog(this).show()
return return
} }
viewModel.resetUserInfo()
// if (equipmentUserInfo.isOtherEquipment()) {
// MainActivity.start(
// context,
// pageType = PageType.PLATE_TIP,
// equipmentUserInfo = equipmentUserInfo,
// isAdmin
// )
// return
// }
if (equipmentUserInfo.equipmentBoxCode?.isNotEmpty() == true) { if (equipmentUserInfo.equipmentBoxCode?.isNotEmpty() == true) {
SerialApi.openPlate( SerialApi.openPlate(
equipmentUserInfo.equipmentBoxCode!!.toInt(), equipmentUserInfo.equipmentBoxCode!!.toInt(),
object : SerialPortManager.SendCallback { object : SerialPortManager.SendCallback {
override fun onSuccess() { override fun onSuccess() {
MainActivity.start(context, pageType = PageType.PLATE_TIP) MainActivity.start(
context,
pageType = PageType.PLATE_TIP,
isAdmin = isAdmin
)
} }
override fun onFail(e: Exception?) { override fun onFail(e: Exception?) {
@@ -338,13 +367,16 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
}) })
} else { } else {
if (isAdmin) { if (isAdmin) {
settingViewModel.getEquipmentList() settingViewModel.getEquipmentList {
loadEquipmentList(it)
}
} else { } else {
Timber.d("无餐盘信息") Timber.d("无餐盘信息")
MainActivity.start( MainActivity.start(
context, context,
pageType = PageType.PLATE_TIP, pageType = PageType.PLATE_TIP,
equipmentUserInfo = equipmentUserInfo equipmentUserInfo = equipmentUserInfo,
isAdmin = isAdmin
) )
} }
} }
@@ -355,4 +387,87 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
keyEventHelper?.onDestroy() keyEventHelper?.onDestroy()
super.onDestroy() super.onDestroy()
} }
private val intervalExecutor by lazy { IntervalExecutor() }
private var faceTaskJob: Job? = null
// private val initialDelay = 5 * 60 * 1000L
// private val dealyMillis = 10 * 60 * 1000L
private val initialDelay = 1 * 60 * 1000L
private val dealyMillis = 1 * 60 * 1000L
private var taskPageNo = 1
fun startFaceTask() {
faceTaskJob =
intervalExecutor.startIntervalTaskWithInitialDelay(initialDelay, dealyMillis) {
getFaceIncrementList()
}
}
private var faceTimestamp = 0L
private fun getFaceIncrementList() {
val timestamp = SpTool.getLastFaceTimestamp()
if (timestamp == 0L) {
return
}
settingViewModel.getFaceIncrementList(
pageNo = taskPageNo,
timestamp = timestamp
) { list ->
runOnUiThread {
if (taskPageNo == 1 && list.isEmpty()) {
//未查询到增量数据
return@runOnUiThread
}
updateFaceData(list)
if (list.size >= settingViewModel.PAGE_SIZE) {
faceTimestamp = list.last().faceUpdateTimestamp?:0
taskPageNo++
getFaceIncrementList()
return@runOnUiThread
}
if (list.isNotEmpty()) {
faceTimestamp = list.last().faceUpdateTimestamp?:0
}
SpTool.setLastFaceTimestamp(faceTimestamp)
}
}
}
private val recognizeViewModel by viewModels<RecognizeViewModel>()
private fun updateFaceData(list: List<UserFaceModel>) {
Thread {
val faceList = mutableListOf<FaceEntity>()
try {
list.forEach { model ->
if (model.faceDeleted == true) {
//删除数据
FaceDatabase.getInstance(this).faceDao().deleteFaceById(model.userId)
} else {
//保存数据
val faceEntity = FaceEntity(
model.userId,
null,
Base64.decode(model.faceFeatureStr)
).also {
it.userType = "1"
}
faceList.add(faceEntity)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
try {
if (faceList.isNotEmpty()) {
FaceDatabase.getInstance(this).faceDao().insert(faceList)
}
recognizeViewModel.refreshFaceList()
} catch (e: Exception) {
e.printStackTrace()
}
}.start()
}
} }
@@ -0,0 +1,91 @@
package com.sw.platecabinet.activity
import android.content.Intent
import android.util.Log
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.databinding.ActivityDeviceInitBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.ext.gone
import com.sw.platecabinet.ext.invisible
import com.sw.platecabinet.viewmodel.SettingViewModel
/**
* 设备初始化界面
*/
class DeviceInitActivity : BaseActivity<ActivityDeviceInitBinding>() {
override fun inflateViewBinding(): ActivityDeviceInitBinding {
return ActivityDeviceInitBinding.inflate(layoutInflater)
}
override fun inflateTitleBinding(): ItemTitleTimeBinding? {
return null
}
override fun initialize() {
// val isSuccess = deviceViewModel.checkEquipmentInfo()
// if (isSuccess) {
// goLoginActivity()
// return
// }
// binding.ivQrCode.setImageBitmap(
// QRCodeUtil.generateQRCode(
// content = GlobalData.deviceId,
// size = 200
// )
// )
// binding.btnInit.setOnClickListener {
// deviceViewModel.getDeviceToken()
// }
// binding.btnInit.gone()
// binding.ivQrCode.invisible()
// binding.root.postDelayed({
// goLoginActivity()
// }, 1000)
showWaitingDialog("加载中……")
viewModel.getDeviceConfig { deviceConfig ->
runOnUiThread {
if (deviceConfig == null) {
hideWaitingDialog()
ToastUtils.showToast("获取设备配置数据失败")
hideWaitingDialog()
goLoginActivity()
return@runOnUiThread
}
GlobalData.appId = deviceConfig.arcsoftAppId ?: ""
GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: ""
GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: ""
binding.root.postDelayed({
hideWaitingDialog()
goLoginActivity()
}, 500)
}
}
// goLoginActivity()
}
override fun registerDataChange() {
super.registerDataChange()
// lifecycleScope.launch {
// deviceViewModel.deviceInfoResult.collect { it ->
// if (it == true) {
// goLoginActivity()
// }
// }
// }
}
private fun goLoginActivity() {
val intent = Intent(this, LoginByFaceActivity::class.java)
startActivity(intent)
finish()
}
override fun onLeftDoubleClick() {
}
}
@@ -1,9 +1,16 @@
package com.sw.platecabinet.activity package com.sw.platecabinet.activity
import android.content.Intent import androidx.lifecycle.lifecycleScope
import com.sw.plate.utils.arcface.FaceApi
import com.sw.plate.utils.arcface.faceserver.FaceServer
import com.sw.platecabinet.databinding.ActivityInitBinding import com.sw.platecabinet.databinding.ActivityInitBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/**
* 待机界面
*/
class InitActivity : BaseActivity<ActivityInitBinding>() { class InitActivity : BaseActivity<ActivityInitBinding>() {
override fun inflateViewBinding(): ActivityInitBinding { override fun inflateViewBinding(): ActivityInitBinding {
return ActivityInitBinding.inflate(layoutInflater) return ActivityInitBinding.inflate(layoutInflater)
@@ -15,9 +22,16 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
override fun initialize() { override fun initialize() {
binding.main.setOnClickListener { binding.main.setOnClickListener {
val intent = Intent(this, LoginByFaceActivity::class.java) finish()
startActivity(intent)
} }
// binding.takeButton.setOnClickListener {
//
// lifecycleScope.launch(Dispatchers.IO) {
// FaceApi().deleteByUserName("288")
// }
//
// finish()
// }
} }
@@ -26,12 +26,18 @@ import com.sw.plate.utils.arcface.camera.DualCameraHelper
import com.sw.plate.utils.arcface.face.constants.LivenessType import com.sw.plate.utils.arcface.face.constants.LivenessType
import com.sw.plate.utils.arcface.face.model.FacePreviewInfo import com.sw.plate.utils.arcface.face.model.FacePreviewInfo
import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration
import com.sw.plate.utils.arcface.faceserver.FaceServer
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import com.sw.platecabinet.R import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.network.task.TaskManager
import com.sw.platecabinet.utils.PermissionHelper import com.sw.platecabinet.utils.PermissionHelper
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import timber.log.Timber import timber.log.Timber
/** /**
@@ -60,8 +66,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
companion object { companion object {
private var instance: LoginByFaceActivity? = null private var instance: LoginByFaceActivity? = null
fun finishActivity() { fun goInitActivity() {
instance?.finish() instance?.goInitActivity()
} }
} }
@@ -74,11 +80,19 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
initArcView() initArcView()
openRectInfoDraw = true openRectInfoDraw = true
recognizeViewModel.setDrawRectInfoTextValue(true) recognizeViewModel.setDrawRectInfoTextValue(true)
viewModel.generateToken() //viewModel.generateToken()
// viewModel.activeEngine()
viewModel.getUserFaceCache()
binding.llToPwd.setOnClickListener { binding.llToPwd.setOnClickListener {
val intent = Intent(this, LoginByPwdActivity::class.java) val intent = Intent(this, LoginByPwdActivity::class.java)
startActivity(intent) startActivity(intent)
} }
// TODO: 测试请求
TaskManager.startTask()
EventBus.getDefault().register(this)
} }
private fun checkCameraPermission() { private fun checkCameraPermission() {
@@ -97,6 +111,13 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
permissionHelper.checkAndRequest() permissionHelper.checkAndRequest()
} }
@Subscribe(threadMode = ThreadMode.MAIN)
fun getFaceEntity(insertEntity: FaceEntity) {
Timber.tag("performSync").e("-time=%s", insertEntity.registerTime)
recognizeViewModel.addFace(insertEntity)
Timber.tag("performSync over").e("-time=%s", insertEntity.registerTime)
}
override fun onLeftDoubleClick() { override fun onLeftDoubleClick() {
finish() finish()
} }
@@ -152,7 +173,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
recognizeViewModel.recognizeUserId.observe(this, Observer { userId: String? -> recognizeViewModel.recognizeUserId.observe(this, Observer { userId: String? ->
Timber.i("recognizeUserId observe userId = $userId") Timber.i("recognizeUserId observe userId = $userId")
viewModel.getUserInfoById(memberId = userId?.toInt() ?: 0) viewModel.getUserInfoById(memberId = userId)
}) })
recognizeViewModel.drawRectInfoText.observe(this, Observer { info -> recognizeViewModel.drawRectInfoText.observe(this, Observer { info ->
@@ -167,6 +188,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
} }
override fun onDestroy() { override fun onDestroy() {
Timber.d("onDestroy")
instance = null instance = null
if (rgbCameraHelper != null) { if (rgbCameraHelper != null) {
rgbCameraHelper!!.release() rgbCameraHelper!!.release()
@@ -175,6 +197,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
recognizeViewModel.destroy() recognizeViewModel.destroy()
EventBus.getDefault().unregister(this)
super.onDestroy() super.onDestroy()
} }
@@ -254,7 +277,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
val layoutParams = adjustPreviewViewSize( val layoutParams = adjustPreviewViewSize(
binding.dualCameraTexturePreviewRgb, binding.dualCameraTexturePreviewRgb,
binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView,
previewSizeRgb, displayOrientation, 0.8f previewSizeRgb, displayOrientation, 0.6f
) )
Timber.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") Timber.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}")
Timber.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") Timber.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}")
@@ -388,6 +411,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
protected override fun onPause() { protected override fun onPause() {
pauseCamera() pauseCamera()
super.onPause() super.onPause()
countDownTimer?.cancel()
} }
private fun pauseCamera() { private fun pauseCamera() {
@@ -398,19 +422,27 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) { override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
super.handleLoginSuccess(equipmentUserInfo, isAdmin) super.handleLoginSuccess(equipmentUserInfo, isAdmin)
finish() // goInitActivity()
} }
fun initCountTime() { fun initCountTime() {
val totalTimeInMillis = 30L * 1000 val totalTimeInMillis = 30L * 1000
countDownTimer = object : CountDownTimer(totalTimeInMillis, 1000) { countDownTimer = object : CountDownTimer(totalTimeInMillis, 1000) {
override fun onTick(millisUntilFinished: Long) { override fun onTick(millisUntilFinished: Long) {
Timber.d("initCountTime onTick = ${(millisUntilFinished / 1000).toInt()}")
binding.tvToInit.text = "${(millisUntilFinished / 1000).toInt() + 1}" binding.tvToInit.text = "${(millisUntilFinished / 1000).toInt() + 1}"
} }
override fun onFinish() { override fun onFinish() {
finish() goInitActivity()
} }
}.start() }.start()
} }
fun goInitActivity() {
val intent = Intent(context, InitActivity::class.java)
startActivity(intent)
}
} }
@@ -4,9 +4,14 @@ import android.content.Intent
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding 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.model.response.EquipmentUserInfo
import com.sw.platecabinet.utils.KeyboardUtils import com.sw.platecabinet.utils.KeyboardUtils
/**
* 密码登录
*/
class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() { class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
override fun inflateViewBinding(): ActivityLoginByPwdBinding { override fun inflateViewBinding(): ActivityLoginByPwdBinding {
@@ -25,7 +30,12 @@ class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
ToastUtils.showToast("手机或校验码不能为空") ToastUtils.showToast("手机或校验码不能为空")
return@setOnClickListener return@setOnClickListener
} }
viewModel.loginWithPwd(phone = phone, password = pwd) val loginParam = LoginParam(
//equipmentId = equipmentId,
phone = phone,
password = pwd
)
viewModel.loginWithPwd(loginParam)
KeyboardUtils.hideKeyboard(this) KeyboardUtils.hideKeyboard(this)
} }
binding.tvFaceRec.setOnClickListener { binding.tvFaceRec.setOnClickListener {
@@ -41,7 +51,12 @@ class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) { override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
super.handleLoginSuccess(equipmentUserInfo, isAdmin) super.handleLoginSuccess(equipmentUserInfo, isAdmin)
LoginByFaceActivity.finishActivity() // val cardBalance = equipmentUserInfo.cardBalance?:0.toDouble()
// val balanceIsNotEnough = cardBalance <= 0.toDouble()
if (equipmentUserInfo.isIntercept) {
return
}
LoginByFaceActivity.goInitActivity()
finish() finish()
} }
} }
@@ -15,6 +15,9 @@ import com.sw.platecabinet.utils.FragmentHelper
typealias Callback = (String) -> Unit typealias Callback = (String) -> Unit
/**
* 主界面,内部嵌套framgnet使用
*/
class MainActivity : BaseActivity<ActivityMainBinding>() { class MainActivity : BaseActivity<ActivityMainBinding>() {
private lateinit var fragmentHelper: FragmentHelper private lateinit var fragmentHelper: FragmentHelper
private var pageType = PageType.SETTING_LIST private var pageType = PageType.SETTING_LIST
@@ -32,27 +35,31 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
companion object { companion object {
private const val PARAM_PAGE_TYPE = "pageType" private const val PARAM_PAGE_TYPE = "pageType"
private const val PARAM_EQUIPMENT_INFO = "equipmentUserInfo" private const val PARAM_EQUIPMENT_INFO = "equipmentUserInfo"
private const val PARAM_IS_ADMIN = "isAdmin"
fun start( fun start(
context: Context, context: Context,
pageType: PageType, pageType: PageType,
equipmentUserInfo: EquipmentUserInfo? = null equipmentUserInfo: EquipmentUserInfo? = null,
isAdmin: Boolean = false
) { ) {
val intent = Intent(context, MainActivity::class.java) val intent = Intent(context, MainActivity::class.java)
intent.putExtra(PARAM_PAGE_TYPE, pageType.name) intent.putExtra(PARAM_PAGE_TYPE, pageType.name)
intent.putExtra(PARAM_EQUIPMENT_INFO, equipmentUserInfo) intent.putExtra(PARAM_EQUIPMENT_INFO, equipmentUserInfo)
intent.putExtra(PARAM_IS_ADMIN, isAdmin)
context.startActivity(intent) context.startActivity(intent)
} }
} }
override fun initialize() { override fun initialize() {
val param = intent.getStringExtra(PARAM_PAGE_TYPE) val param = intent.getStringExtra(PARAM_PAGE_TYPE)
val isAdmin = intent.getBooleanExtra(PARAM_IS_ADMIN, false)
val equipmentUserInfo = intent.getParcelableExtra<EquipmentUserInfo>(PARAM_EQUIPMENT_INFO) val equipmentUserInfo = intent.getParcelableExtra<EquipmentUserInfo>(PARAM_EQUIPMENT_INFO)
pageType = param?.let { PageType.valueOf(param) } ?: PageType.SETTING_LIST pageType = param?.let { PageType.valueOf(param) } ?: PageType.SETTING_LIST
fragmentHelper = FragmentHelper(supportFragmentManager, R.id.fragment_container) fragmentHelper = FragmentHelper(supportFragmentManager, R.id.fragment_container)
val page = when (pageType) { val page = when (pageType) {
PageType.SETTING_LIST -> SettingListFragment() PageType.SETTING_LIST -> SettingListFragment()
PageType.BIND_PLATE -> BindPlateFragment.newInstance(equipmentUserInfo) PageType.BIND_PLATE -> BindPlateFragment.newInstance(equipmentUserInfo)
PageType.PLATE_TIP -> PlateOpenFragment.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() PageType.PLATE_CABINET_FULL -> PlateCabinetFullFragment()
} }
@@ -11,6 +11,9 @@ import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.ext.dp import com.sw.platecabinet.ext.dp
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
/**
* 解绑确认弹窗界面
*/
class UnBindDialogActivity : BaseActivity<ActivityUnbindDialogBinding>() { class UnBindDialogActivity : BaseActivity<ActivityUnbindDialogBinding>() {
private var equipmentUserInfo: EquipmentUserInfo? = null private var equipmentUserInfo: EquipmentUserInfo? = null
@@ -0,0 +1,36 @@
package com.sw.platecabinet.dialog
import android.app.Dialog
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Window
import androidx.fragment.app.FragmentActivity
import com.sw.platecabinet.databinding.DialogBalanceNotEnoughBinding
import com.sw.platecabinet.ext.dp
open class BalanceNotEnoughDialog(
private var activity: FragmentActivity
) : Dialog(activity) {
private lateinit var binding: DialogBalanceNotEnoughBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
binding = DialogBalanceNotEnoughBinding.inflate(layoutInflater)
setContentView(binding.root)
window?.run {
attributes = attributes.apply {
width = 480.dp
}
setBackgroundDrawable(ColorDrawable())
setCancelable(false)
}
addListener()
}
private fun addListener() {
binding.tvConfirm.setOnClickListener { dismiss() }
}
}
@@ -0,0 +1,38 @@
package com.sw.platecabinet.dialog
import android.app.Dialog
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Window
import androidx.fragment.app.FragmentActivity
import com.sw.platecabinet.databinding.DialogUserBindRemindBinding
import com.sw.platecabinet.ext.dp
open class UserBindRemindDialog(
private var activity: FragmentActivity,
var content:String
) : Dialog(activity) {
private lateinit var binding: DialogUserBindRemindBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
binding = DialogUserBindRemindBinding.inflate(layoutInflater)
setContentView(binding.root)
window?.run {
attributes = attributes.apply {
width = 480.dp
}
setBackgroundDrawable(ColorDrawable())
setCancelable(false)
}
binding.tvBindContent.text = content
addListener()
}
private fun addListener() {
binding.tvConfirm.setOnClickListener { dismiss() }
}
}
@@ -2,6 +2,7 @@ package com.sw.platecabinet.ext
import android.content.res.Resources import android.content.res.Resources
import android.util.TypedValue import android.util.TypedValue
import android.view.View
import androidx.annotation.Dimension import androidx.annotation.Dimension
/** /**
@@ -50,4 +51,16 @@ val Float.sp: Float
fun formatNumber(num: String): String { fun formatNumber(num: String): String {
return num.padStart(2, '0') return num.padStart(2, '0')
}
fun View.visible() {
visibility = View.VISIBLE
}
fun View.invisible() {
visibility = View.INVISIBLE
}
fun View.gone() {
visibility = View.GONE
} }
@@ -1,10 +1,12 @@
package com.sw.platecabinet.fragment package com.sw.platecabinet.fragment
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextUtils import android.text.TextUtils
import android.text.TextWatcher import android.text.TextWatcher
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@@ -20,12 +22,17 @@ import com.sw.platecabinet.adapter.GridSpacingItemDecoration
import com.sw.platecabinet.adapter.dpToPx import com.sw.platecabinet.adapter.dpToPx
import com.sw.platecabinet.databinding.FragmentBindPlateBinding import com.sw.platecabinet.databinding.FragmentBindPlateBinding
import com.sw.platecabinet.databinding.ItemSearchUserInfoBinding import com.sw.platecabinet.databinding.ItemSearchUserInfoBinding
import com.sw.platecabinet.dialog.UserBindRemindDialog
import com.sw.platecabinet.ext.maskName import com.sw.platecabinet.ext.maskName
import com.sw.platecabinet.ext.maskPhone 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.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.utils.Debouncer import com.sw.platecabinet.utils.Debouncer
import com.sw.platecabinet.utils.KeyboardUtils import com.sw.platecabinet.utils.KeyboardUtils
import com.sw.platecabinet.viewmodel.SettingViewModel
import com.sw.platecabinet.viewmodel.UserViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@@ -42,6 +49,8 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
private var lastText = "" private var lastText = ""
private val debouncer = Debouncer(2000) private val debouncer = Debouncer(2000)
private val userViewModel by viewModels<UserViewModel>()
companion object { companion object {
@JvmStatic @JvmStatic
fun newInstance(userInfo: EquipmentUserInfo?) = fun newInstance(userInfo: EquipmentUserInfo?) =
@@ -52,13 +61,18 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
} }
} }
@SuppressLint("SetTextI18n")
override fun initialize() { override fun initialize() {
arguments?.let { arguments?.let { args ->
info = it.getParcelable(KEY_ACTION_TYPE) info = args.getParcelable(KEY_ACTION_TYPE)
info?.let { info?.let {
binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}" binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}"
if (!TextUtils.isEmpty(it.plateNumber)) { if (!TextUtils.isEmpty(it.plateNumber)) {
binding.etCode.text = Editable.Factory.getInstance().newEditable(it.plateNumber) // binding.etCode.text = Editable.Factory.getInstance().newEditable(it.plateNumber)
binding.etCode.apply {
setText(it.plateNumber)
setSelection(length())
}
} }
} }
} }
@@ -96,13 +110,27 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
} }
}) })
(activity as MainActivity).registerKeyEventInfo { (activity as MainActivity).registerKeyEventInfo {
if (binding.etUserInfo.isFocused) return@registerKeyEventInfo // binding.etCode.text.clear()
binding.etCode.text.clear() // binding.etCode.postDelayed({
binding.etCode.postDelayed({ // binding.etCode.text.clear()
binding.etCode.text.clear() // binding.etCode.text = Editable.Factory.getInstance().newEditable(it)
binding.etCode.text = Editable.Factory.getInstance().newEditable(it) activity?.runOnUiThread {
binding.etUserInfo.requestFocus() if (binding.etUserInfo.isFocused) {
}, 50) 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)
} }
} }
@@ -161,6 +189,10 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
} }
} }
binding.llBind.setOnClickListener { binding.llBind.setOnClickListener {
if (equipmentBoxCode.isNullOrBlank().not()) {
showBindDialog()
return@setOnClickListener
}
if (info == null || info!!.equipmentCode?.isEmpty() == true || info!!.equipmentBoxCode?.isEmpty() == true) { if (info == null || info!!.equipmentCode?.isEmpty() == true || info!!.equipmentBoxCode?.isEmpty() == true) {
ToastUtils.showToast("传入的设备信息异常") ToastUtils.showToast("传入的设备信息异常")
return@setOnClickListener return@setOnClickListener
@@ -178,13 +210,16 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
ToastUtils.showToast("选中的会员信息异常") ToastUtils.showToast("选中的会员信息异常")
return@setOnClickListener return@setOnClickListener
} }
val bindParam = BindParam(
viewModel.bindPlate( equipmentId = info?.equipmentId,
equipmentCode = info!!.equipmentCode!!, equipmentCode = info?.equipmentCode,
equipmentBoxCode = info!!.equipmentBoxCode!!, equipmentBoxCode = info?.equipmentBoxCode,
memberId = checkedItem!!.id!!, faceId = checkedItem?.faceId,
plateNumber = plateNumber plateNumber = plateNumber
) )
viewModel.bindPlate(bindParam) { pair ->
updateBindState(pair)
}
KeyboardUtils.hideKeyboard(requireActivity()) KeyboardUtils.hideKeyboard(requireActivity())
} }
binding.tvBack.setOnClickListener { activity?.finish() } binding.tvBack.setOnClickListener { activity?.finish() }
@@ -200,40 +235,11 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
adapter.updateData(it) adapter.updateData(it)
} }
} }
lifecycleScope.launch { // lifecycleScope.launch {
viewModel.bindStateChange.collect { // viewModel.bindStateChange.collect {
if (it.first == null) return@collect // 解绑状态过滤 // updateBindState(it)
val errorInfo = it.second // }
if (errorInfo.isSuccess()) { // }
if (errorInfo.equipmentUserInfo == null) {
ToastUtils.showToast("数据异常")
return@collect
}
if (errorInfo.equipmentUserInfo.isOtherEquipment() == true) {
MainActivity.start(
requireContext(),
pageType = PageType.PLATE_TIP,
equipmentUserInfo = errorInfo.equipmentUserInfo
)
} 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)
}
}
}
} }
private fun createAdapter(): GenericItemAdapter<SearchResult.Member, ItemSearchUserInfoBinding> { private fun createAdapter(): GenericItemAdapter<SearchResult.Member, ItemSearchUserInfoBinding> {
@@ -253,8 +259,59 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
Timber.d("itemClick ${item.name}, position = $position") Timber.d("itemClick ${item.name}, position = $position")
checkedItem = item checkedItem = item
adapter.notifyDataSetChanged() 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)
}
}
} }
@@ -1,9 +1,11 @@
package com.sw.platecabinet.fragment package com.sw.platecabinet.fragment
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.CountDownTimer import android.os.CountDownTimer
import com.sw.platecabinet.Constants import com.sw.platecabinet.Constants
import com.sw.platecabinet.R import com.sw.platecabinet.R
import com.sw.platecabinet.activity.InitActivity
import com.sw.platecabinet.databinding.FragmentPlateOpenBinding import com.sw.platecabinet.databinding.FragmentPlateOpenBinding
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
@@ -14,14 +16,17 @@ class PlateOpenFragment :
BaseFragment<FragmentPlateOpenBinding>(FragmentPlateOpenBinding::inflate) { BaseFragment<FragmentPlateOpenBinding>(FragmentPlateOpenBinding::inflate) {
private var totalTimeInMillis: Long = Constants.AUTO_CLOSE_TIME * 1000 private var totalTimeInMillis: Long = Constants.AUTO_CLOSE_TIME * 1000
internal val KEY_ACTION_TYPE = "actionType" internal val KEY_ACTION_TYPE = "actionType"
internal val PARAM_IS_ADMIN = "isAdmin"
private var info: EquipmentUserInfo? = null private var info: EquipmentUserInfo? = null
private var isAdmin: Boolean = false
companion object { companion object {
@JvmStatic @JvmStatic
fun newInstance(userInfo: EquipmentUserInfo?) = fun newInstance(userInfo: EquipmentUserInfo?, isAdmin: Boolean) =
PlateOpenFragment().apply { PlateOpenFragment().apply {
arguments = Bundle().apply { arguments = Bundle().apply {
putParcelable(KEY_ACTION_TYPE, userInfo) putParcelable(KEY_ACTION_TYPE, userInfo)
putBoolean(PARAM_IS_ADMIN, isAdmin)
} }
} }
} }
@@ -29,6 +34,7 @@ class PlateOpenFragment :
override fun initialize() { override fun initialize() {
arguments?.let { arguments?.let {
info = it.getParcelable(KEY_ACTION_TYPE) info = it.getParcelable(KEY_ACTION_TYPE)
isAdmin = it.getBoolean(PARAM_IS_ADMIN)
info?.let { info?.let {
if (!it.hasEquipmentBox()) { if (!it.hasEquipmentBox()) {
binding.ivType.setImageResource(R.drawable.ic_tip_warn) binding.ivType.setImageResource(R.drawable.ic_tip_warn)
@@ -60,6 +66,10 @@ class PlateOpenFragment :
override fun onFinish() { override fun onFinish() {
activity?.finish() activity?.finish()
if (!isAdmin) {
val intent = Intent(context, InitActivity::class.java)
startActivity(intent)
}
} }
}.start() }.start()
} }
@@ -47,12 +47,12 @@ class SettingListFragment :
override fun registerDataChange() { override fun registerDataChange() {
super.registerDataChange() super.registerDataChange()
lifecycleScope.launch { // lifecycleScope.launch {
viewModel.equipmentList.collect { it -> // viewModel.equipmentList.collect { it ->
Timber.d("registerDateChange updateAdapter it = $it") // Timber.d("registerDateChange updateAdapter it = $it")
updateAdapter(it) // updateAdapter(it)
} // }
} // }
} }
override fun initialize() { override fun initialize() {
@@ -80,7 +80,9 @@ class SettingListFragment :
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
viewModel.getEquipmentList() viewModel.getEquipmentList{
updateAdapter(it)
}
} }
private fun createItemAdapter(): GenericItemAdapter<EquipmentUserInfo, ItemBindViewBinding> { private fun createItemAdapter(): GenericItemAdapter<EquipmentUserInfo, ItemBindViewBinding> {
@@ -168,7 +170,11 @@ class SettingListFragment :
SerialApi.openPlate(equipmentBoxCode, object : SerialPortManager.SendCallback { SerialApi.openPlate(equipmentBoxCode, object : SerialPortManager.SendCallback {
override fun onSuccess() { override fun onSuccess() {
hideWaitingDialog() hideWaitingDialog()
MainActivity.start(requireContext(), pageType = PageType.PLATE_TIP) MainActivity.start(
requireContext(),
pageType = PageType.PLATE_TIP,
isAdmin = true
)
} }
override fun onFail(e: Exception?) { override fun onFail(e: Exception?) {
@@ -12,6 +12,7 @@ import com.sw.platecabinet.activity.UnBindDialogActivity
import com.sw.platecabinet.databinding.FragmentUnbindPlateBinding import com.sw.platecabinet.databinding.FragmentUnbindPlateBinding
import com.sw.platecabinet.ext.maskName import com.sw.platecabinet.ext.maskName
import com.sw.platecabinet.ext.maskPhone import com.sw.platecabinet.ext.maskPhone
import com.sw.platecabinet.model.ErrorInfo
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -38,16 +39,15 @@ class UnBindPlateFragment private constructor() : BaseFragment<FragmentUnbindPla
ActivityResultContracts.StartActivityForResult() ActivityResultContracts.StartActivityForResult()
) { result -> ) { result ->
if (result.resultCode == Activity.RESULT_OK) { if (result.resultCode == Activity.RESULT_OK) {
viewModel.unbindPlate( viewModel.unbindPlate(info?.id) { pair ->
equipmentBoxCode = info!!.equipmentBoxCode!!, updateBindState(pair)
equipmentCode = info!!.equipmentCode!! }
)
} }
} }
override fun initialize() { override fun initialize() {
arguments?.let { arguments?.let { args ->
info = it.getParcelable(ARG_PARAM1) info = args.getParcelable(ARG_PARAM1)
info?.let { info?.let {
binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}" binding.tvNum.text = "${it.equipmentName}-${it.equipmentBoxCode}"
binding.tvPlateNumberValue.text = it.plateNumber binding.tvPlateNumberValue.text = it.plateNumber
@@ -73,20 +73,23 @@ class UnBindPlateFragment private constructor() : BaseFragment<FragmentUnbindPla
override fun registerDataChange() { override fun registerDataChange() {
super.registerDataChange() super.registerDataChange()
lifecycleScope.launch { // lifecycleScope.launch {
viewModel.bindStateChange.collect { // viewModel.bindStateChange.collect {
if (it.first == null) return@collect // 绑定状态过滤 // updateBindState(it)
val errorInfo = it.second // }
if (errorInfo.isSuccess()) { // }
ToastUtils.showToast("解绑成功") }
private fun updateBindState(pair: Pair<Boolean?, ErrorInfo>){
if (pair.first == null) return // 绑定状态过滤
val errorInfo = pair.second
if (errorInfo.isSuccess()) {
ToastUtils.showToast("解绑成功")
// activity?.finish() // activity?.finish()
// 关闭宿主 Activity // 关闭宿主 Activity
requireActivity().finish() requireActivity().finish()
requireActivity().overridePendingTransition(0, 0) requireActivity().overridePendingTransition(0, 0)
} else { } else {
ToastUtils.showToast(errorInfo.msg) ToastUtils.showToast(errorInfo.msg)
}
}
} }
} }
} }
@@ -6,11 +6,22 @@ import com.sw.platecabinet.model.response.EquipmentUserInfo
* 错误信息 code == 200 成功 * 错误信息 code == 200 成功
*/ */
data class ErrorInfo( data class ErrorInfo(
val code: Int = 200, val code: String = "00000",
val msg: String = "", val msg: String = "",
val equipmentUserInfo: EquipmentUserInfo? = null val equipmentUserInfo: EquipmentUserInfo? = null
) { ) {
fun isSuccess(): Boolean { fun isSuccess(): Boolean {
return code == 200 return code == "00000"
} }
} }
data class DeviceConfig(
var arcsoftAppId: String? = null,
var arcsoftSdkKey: String? = null,
var arcsoftActiveKey: String? = null
)
data class CodeMsg(
val code: String? = "",
val msg: String? = ""
)
@@ -12,28 +12,25 @@ import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class BindParam( data class BindParam(
/** /**
* app版本号 * 设备Id
*/ */
var appVersion: String = "", val equipmentId: String? = null,
/** /**
* 设备ID * 设备编号
*/ */
@SerializedName("equipmentCode") var equipmentCode: String? = "",
var equipmentCode: String = "",
/** /**
*设备盒子编号 *设备盒子编号
*/ */
@SerializedName("equipmentBoxCode")
val equipmentBoxCode: String? = null, val equipmentBoxCode: String? = null,
/** /**
* *
* 会员Id * 会员Id
*/ */
@SerializedName("memberId") val memberId: String? = null,
val memberId: Int? = null, val faceId: String? = null,
/** /**
*餐盘编号 *餐盘编号
*/ */
@SerializedName("plateNumber")
val plateNumber: String? = null val plateNumber: String? = null
) : Parcelable ) : Parcelable
@@ -11,27 +11,20 @@ import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class LoginParam( data class LoginParam(
/** /**
* app版本号 * 设备Id
*/ */
var appVersion: String = "", val equipmentId: Int? = null,
/**
* 设备ID
*/
@SerializedName("equipmentCode")
var equipmentCode: String = "",
/** /**
* 会员信息 * 会员信息
*/ */
@SerializedName("memberId") // val memberId: String? = null,
val memberId: Int? = null, val faceId: String? = null,
/** /**
* 密码 * 密码
*/ */
@SerializedName("password")
val password: String? = null, val password: String? = null,
/** /**
* 手机号 * 手机号
*/ */
@SerializedName("phone")
val phone: String? = null val phone: String? = null
) : Parcelable ) : Parcelable
@@ -10,25 +10,27 @@ import kotlinx.parcelize.Parcelize
*/ */
@Parcelize @Parcelize
data class SearchParam( data class SearchParam(
/** // /**
* app版本号 // * app版本号
*/ // */
var appVersion: String = "", // var appVersion: String = "",
/** // /**
* 设备ID // * 设备ID
*/ // */
@SerializedName("equipmentCode") // @SerializedName("equipmentCode")
var equipmentCode: String = "", // var equipmentCode: String = "",
@SerializedName("consumptionTime") // @SerializedName("consumptionTime")
val consumptionTime: List<String?>? = listOf(), // val consumptionTime: List<String?>? = listOf(),
@SerializedName("createTime") // @SerializedName("createTime")
val createTime: List<String?>? = listOf(), // val createTime: List<String?>? = listOf(),
@SerializedName("memberFrom") // @SerializedName("memberFrom")
val memberFrom: Int? = 0, // val memberFrom: Int? = 0,
@SerializedName("pageNum") // @SerializedName("pageNum")
val pageNum: Int? = 0, var pageNum: Int? = 0,
@SerializedName("pageSize") // @SerializedName("pageSize")
val pageSize: Int? = 0, var pageSize: Int? = 0,
@SerializedName("param") // @SerializedName("param")
val `param`: String? = "" // val `param`: String? = "",
var name:String?=null,
var phone:String?=null
) : Parcelable ) : Parcelable
@@ -1,10 +1,12 @@
package com.sw.platecabinet.model.response package com.sw.platecabinet.model.response
data class ApiResponse<T>( data class ApiResponse<T>(
val code: Int, val code: String,
val success: Boolean? = false, // val success: Boolean? = false,
val msg: String? = "", val msg: String? = "",
val data: T? = null val data: T? = null,
// val result: T? = null,
) { ) {
fun isSuccess(): Boolean = code == 200 // fun isSuccess(): Boolean = code == 200
fun isSuccess(): Boolean = code == "00000"
} }
@@ -0,0 +1,72 @@
package com.sw.platecabinet.model.response
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class EquipmentInfo(
@SerializedName("appPackageLocalUrl")
val appPackageLocalUrl: String? = "",
@SerializedName("appPackageUrl")
val appPackageUrl: String? = "",
@SerializedName("arcsoftActiveKey")
val arcsoftActiveKey: String? = "",
@SerializedName("arcsoftAppId")
val arcsoftAppId: String? = "",
@SerializedName("arcsoftSdkKey")
val arcsoftSdkKey: String? = "",
@SerializedName("arrayCross")
val arrayCross: Int? = 0,
@SerializedName("arrayMode")
val arrayMode: String? = "",
@SerializedName("arrayVertical")
val arrayVertical: Int? = 0,
@SerializedName("canteenId")
val canteenId: String? = "",
@SerializedName("canteenName")
val canteenName: String? = "",
@SerializedName("clientServerIp")
val clientServerIp: String? = "",
@SerializedName("createBy")
val createBy: String? = "",
@SerializedName("createTime")
val createTime: String? = "",
@SerializedName("customerName")
val customerName: String? = "",
@SerializedName("equipmentCode")
val equipmentCode: String? = "",
@SerializedName("equipmentName")
val equipmentName: String? = "",
@SerializedName("equipmentName_dictText")
val equipmentNameDictText: String? = "",
@SerializedName("id")
val id: String? = "",
@SerializedName("isSync")
val isSync: Int? = 0,
@SerializedName("mqName")
val mqName: String? = "",
@SerializedName("mqPassword")
val mqPassword: String? = "",
@SerializedName("orgCode")
val orgCode: String? = "",
@SerializedName("owningTrack")
val owningTrack: Int? = 0,
@SerializedName("owningTrackOrder")
val owningTrackOrder: Int? = 0,
@SerializedName("screenHtml")
val screenHtml: String? = "",
@SerializedName("serviceRequestAddress")
val serviceRequestAddress: String? = "",
@SerializedName("status")
val status: Int? = 0,
@SerializedName("sysOrgCode")
val sysOrgCode: String? = "",
@SerializedName("updateBy")
val updateBy: String? = "",
@SerializedName("updateTime")
val updateTime: String? = "",
@SerializedName("zhstServerIp")
val zhstServerIp: String? = ""
) : Parcelable
@@ -1,9 +1,8 @@
package com.sw.platecabinet.model.response package com.sw.platecabinet.model.response
import android.os.Parcelable import android.os.Parcelable
import android.text.TextUtils import android.text.TextUtils
import com.google.gson.annotations.SerializedName //import com.google.gson.annotations.SerializedName
import com.sw.platecabinet.GlobalData import com.sw.platecabinet.GlobalData
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@@ -13,59 +12,65 @@ import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class EquipmentUserInfo( data class EquipmentUserInfo(
/** /**
* 设备盒子编号 * 主键
*/ */
@SerializedName("equipmentBoxCode") val id: Long? = 0,
var equipmentBoxCode: String? = "",
/**
* 设备编号
*/
@SerializedName("equipmentCode")
var equipmentCode: String? = "",
/** /**
* *
* 设备Id * 设备Id
*/ */
@SerializedName("equipmentId")
val equipmentId: String? = "", val equipmentId: String? = "",
/** /**
* 设备名称 * 设备编号
*/ */
@SerializedName("equipmentName") var equipmentCode: String? = "",
val equipmentName: String? = "",
/** /**
* 主键 * 设备盒子编号
*/ */
@SerializedName("id") var equipmentBoxCode: String? = "",
val id: Int? = 0,
/** /**
* 会员Id * 会员Id
*/ */
@SerializedName("memberId") val faceId: String? = "",
val memberId: Int? = 0,
@SerializedName("name")
val name: String? = "",
@SerializedName("phone")
val phone: String? = "",
/** /**
* 餐盘编号 * 餐盘编号
*/ */
@SerializedName("plateNumber")
var plateNumber: String? = "", var plateNumber: String? = "",
/**
* 设备名称
*/
val equipmentName: String? = "",
val orderNo: String? = "",
/** /**
* *
* 更新时间 * 更新时间
*/ */
@SerializedName("updateTime") val updateTime: String? = "",
val 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,
var cardBalance: Double? = 0.toDouble(),
/**
* 用于cardBalance后续拦截判断
*/
var showBalanceNotEnoughDialog: Boolean = false,
var isIntercept: Boolean = false
) : Parcelable { ) : Parcelable {
/** /**
* 是否已绑定 * 是否已绑定
*/ */
fun isBound(): Boolean { fun isBound(): Boolean {
return memberId != null return faceId != null
} }
/** /**
@@ -49,33 +49,37 @@ data class SearchResult(
) : Parcelable { ) : Parcelable {
@Parcelize @Parcelize
data class Member( data class Member(
@SerializedName("cardBalance") // @SerializedName("cardBalance")
val cardBalance: String? = "", // val cardBalance: String? = "",
@SerializedName("cardCode") // @SerializedName("cardCode")
val cardCode: String? = "", // val cardCode: String? = "",
@SerializedName("consumptionCount") // @SerializedName("consumptionCount")
val consumptionCount: Int? = 0, // val consumptionCount: Int? = 0,
@SerializedName("consumptionTotal") // @SerializedName("consumptionTotal")
val consumptionTotal: String? = "", // val consumptionTotal: String? = "",
@SerializedName("createTime") // @SerializedName("createTime")
val createTime: String? = "", // val createTime: String? = "",
@SerializedName("firstTopUpTime") // @SerializedName("firstTopUpTime")
val firstTopUpTime: String? = "", // val firstTopUpTime: String? = "",
@SerializedName("id") // @SerializedName("id")
val id: Int? = 0, // val id: Int? = 0,
@SerializedName("integralBalance") // @SerializedName("integralBalance")
val integralBalance: Int? = 0, // val integralBalance: Int? = 0,
@SerializedName("lastConsumptionTime") // @SerializedName("lastConsumptionTime")
val lastConsumptionTime: String? = "", // val lastConsumptionTime: String? = "",
@SerializedName("memberFrom") // @SerializedName("memberFrom")
val memberFrom: Int? = 0, // val memberFrom: Int? = 0,
@SerializedName("name") // @SerializedName("name")
// val name: String? = "",
// @SerializedName("phone")
// val phone: String? = "",
// @SerializedName("rewardBalance")
// val rewardBalance: String? = "",
// @SerializedName("topUpBalance")
// val topUpBalance: String? = ""
val id: String? = "",
val faceId: String? = "",
val name: String? = "", val name: String? = "",
@SerializedName("phone")
val phone: String? = "", val phone: String? = "",
@SerializedName("rewardBalance")
val rewardBalance: String? = "",
@SerializedName("topUpBalance")
val topUpBalance: String? = ""
) : Parcelable ) : Parcelable
} }
@@ -10,14 +10,21 @@ import kotlinx.parcelize.Parcelize
*/ */
@Parcelize @Parcelize
data class UserFaceModel( data class UserFaceModel(
@SerializedName("faceFeature") // @SerializedName("faceFeature")
val faceFeature: String? = "", // val faceFeature: String? = "",
@SerializedName("faceFeatureString") // @SerializedName("faceFeatureString")
val faceFeatureString: String? = "", // val faceFeatureString: String? = "",
@SerializedName("faceType") // @SerializedName("faceType")
val faceType: String? = "", // val faceType: String? = "",
@SerializedName("userFaceId") // @SerializedName("userFaceId")
val userFaceId: String? = "", // val userFaceId: String? = "",
@SerializedName("userId") // @SerializedName("userId")
val userId: String? = "" // val userId: String? = "",
// @SerializedName("updateTimeStamp")
// val updateTimeStamp: Long = 0,
val userId: String? = "",
val faceFeatureStr: String? = "",
val faceUpdateTimestamp:Long?=null,
val faceDeleted: Boolean?=false
) : Parcelable ) : Parcelable
@@ -1,5 +1,6 @@
package com.sw.platecabinet.network package com.sw.platecabinet.network
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.MyApp import com.sw.platecabinet.MyApp
import com.sw.platecabinet.network.api.ApiService import com.sw.platecabinet.network.api.ApiService
import com.sw.platecabinet.network.interceptor.RequestInterceptor import com.sw.platecabinet.network.interceptor.RequestInterceptor
@@ -11,12 +12,13 @@ import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
object ApiClient { object ApiClient {
private const val BASE_URL = "https://vip.shuziweidao.com" //private const val BASE_URL = "https://vip.shuziweidao.com"
// private const val DEVICE_BASE_URL = "http://device.shuziweidao.com:8889/"
// private const val BASE_URL = "http://192.168.1.8:9092" private var DEVICE_BASE_URL = GlobalData.appBaseUrl
// private const val BASE_URL = "http://192.168.1.8:9092"
private const val TIME_OUT = 30L // 超时时间(秒) private const val TIME_OUT = 30L // 超时时间(秒)
private val okHttpClient = OkHttpClient.Builder() val okHttpClient = OkHttpClient.Builder()
.connectTimeout(TIME_OUT, TimeUnit.SECONDS) .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
.readTimeout(TIME_OUT, TimeUnit.SECONDS) .readTimeout(TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(TIME_OUT, TimeUnit.SECONDS) .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
@@ -33,7 +35,7 @@ object ApiClient {
.build() .build()
private val retrofit = Retrofit.Builder() private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL) .baseUrl(DEVICE_BASE_URL)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
// .addCallAdapterFactory(CoroutineCallAdapterFactory()) // 协程适配器 // .addCallAdapterFactory(CoroutineCallAdapterFactory()) // 协程适配器
@@ -1,66 +1,189 @@
package com.sw.platecabinet.network.api package com.sw.platecabinet.network.api
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.model.DeviceConfig
import com.sw.platecabinet.model.request.BindParam import com.sw.platecabinet.model.request.BindParam
import com.sw.platecabinet.model.request.EquipmentParam import com.sw.platecabinet.model.request.EquipmentParam
import com.sw.platecabinet.model.request.LoginParam import com.sw.platecabinet.model.request.LoginParam
import com.sw.platecabinet.model.request.SearchParam import com.sw.platecabinet.model.request.SearchParam
import com.sw.platecabinet.model.response.ApiResponse import com.sw.platecabinet.model.response.ApiResponse
import com.sw.platecabinet.model.response.EquipmentInfo
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.model.response.UserFaceModel
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Query import retrofit2.http.Query
import retrofit2.http.Url
interface ApiService { interface ApiService {
// /**
/** // * device获取token
* 生成token // */
*/ // @GET("sys/getEquipmentToken")
@GET("/shuwei-zhct/scales/generateToken") // suspend fun getDeviceToken(
suspend fun generateToken( // @Query("qrcodeId") qrcodeId: String,
@Query("deviceId") deviceId: String, // @Query("appVersion") appVersion: String = GlobalData.appVersion
@Query("appVersion") appVersion: String, // ): ApiResponse<String>
@Query("equipmentCode") equipmentCode: String //
): ApiResponse<String> // /**
// *获取配置信息
// */
// @GET("equipment/stEquipment/queryByEquipmentCode")
// suspend fun getDeviceInfo(
// @Query("equipmentCode") equipmentCode: String,
// @Query("appVersion") appVersion: String = GlobalData.appVersion,
// @Header("X-Access-Token") token: String
// ): ApiResponse<EquipmentInfo>
//
// /**
// * 生成token
// */
// @GET//("/shuwei-zhct/scales/generateToken")
// suspend fun generateToken(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/scales/generateToken",
// @Query("deviceId") deviceId: String,
// @Query("appVersion") appVersion: String,
// @Query("equipmentCode") equipmentCode: String
// ): ApiResponse<String>
/** /**
* 获取人脸数据 * 获取人脸数据
*/ */
@GET("/shuwei-zhct/scales/getUserFaceCache") // @GET//("/shuwei-zhct/scales/getUserFaceCache")
// suspend fun getUserFaceCache(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/scales/getUserFaceCache",
// @Query("appVersion") appVersion: String,
// @Query("equipmentCode") equipmentCode: String
// ): ApiResponse<List<UserFaceModel>>
@POST
suspend fun getUserFaceCache( suspend fun getUserFaceCache(
@Query("appVersion") appVersion: String, @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/common/app/faceFeature/list",
@Query("equipmentCode") equipmentCode: String @Body param: Map<String, Int>
): ApiResponse<List<UserFaceModel>> ): ApiResponse<List<UserFaceModel>>
/** // /**
// * 餐盘用户信息获取
// */
// @POST//("/shuwei-zhct/swEquipmentRelUser/equipmentBoxLogin")
// suspend fun equipmentBoxLogin(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/equipmentBoxLogin",
// @Body param: LoginParam
// ): ApiResponse<EquipmentUserInfo>
/**
* 餐盘用户信息获取 * 餐盘用户信息获取
*/ */
@POST("/shuwei-zhct/swEquipmentRelUser/equipmentBoxLogin") @POST//("/shuwei-zhct/swEquipmentRelUser/equipmentBoxLogin")
suspend fun equipmentBoxLogin(@Body param: LoginParam): ApiResponse<EquipmentUserInfo> suspend fun equipmentBoxLogin(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/sideboard/app/getPlateBoxUserInfo",
@Body param: LoginParam
): ApiResponse<EquipmentUserInfo>
/** /**
* 餐盘用户信息列表查询 * 餐盘用户信息列表查询
*/ */
@POST("/shuwei-zhct/swEquipmentRelUser/list") // @POST//("/shuwei-zhct/swEquipmentRelUser/list")
suspend fun getEquipmentList(@Body param: EquipmentParam): ApiResponse<List<EquipmentUserInfo>> // suspend fun getEquipmentList(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/list",
// @Body param: EquipmentParam
// ): ApiResponse<List<EquipmentUserInfo>>
@GET
suspend fun getEquipmentList(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/sideboard/app/getYxMemberRefPlateByEquipmentCode",
): ApiResponse<List<EquipmentUserInfo>>
// /**
// * 餐盘用户信息绑定解绑
// */
// @POST//("/shuwei-zhct/swEquipmentRelUser/addOrEdit")
// suspend fun bindEquipment(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/addOrEdit",
// @Body param: BindParam
// ): ApiResponse<EquipmentUserInfo?>
/** /**
* 餐盘用户信息绑定解 * 餐盘绑
*/ */
@POST("/shuwei-zhct/swEquipmentRelUser/addOrEdit") @POST
suspend fun bindEquipment(@Body param: BindParam): ApiResponse<EquipmentUserInfo?> suspend fun plateBind(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/sideboard/app/plateBinding",
@Body param: BindParam
): ApiResponse<EquipmentUserInfo?>
/**
* 餐盘解绑
*/
@POST
@FormUrlEncoded
suspend fun plateUnbind(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/sideboard/app/plateUnbind",
@Field("id") id: Long?
): ApiResponse<Any?>
/** /**
* 用户信息模糊搜索 * 用户信息模糊搜索
*/ */
@POST("/shuwei-user/swclientUserInfoShop/selectList") @POST//("/shuwei-user/swclientUserInfoShop/selectList")
suspend fun searchUser(@Body param: SearchParam): ApiResponse<SearchResult> suspend fun searchUser(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-user/swclientUserInfoShop/selectList",
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/common/app/getUserInfoByNameOrPhone",
@Body param: SearchParam
): ApiResponse<List<SearchResult.Member>?>
/** // /**
// * 通过餐盘号获取信息
// */
// @POST//("/shuwei-zhct/swEquipmentRelUser/findByPlateNumber")
// suspend fun findByPlateNumber(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/findByPlateNumber",
// @Body param: BindParam
// ): ApiResponse<EquipmentUserInfo>
/**
* 通过餐盘号获取信息 * 通过餐盘号获取信息
*/ */
@POST("/shuwei-zhct/swEquipmentRelUser/findByPlateNumber") @GET
suspend fun findByPlateNumber(@Body param: BindParam): ApiResponse<EquipmentUserInfo> suspend fun findByPlateNumber(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/sideboard/app/getMemberRefPlateByPlateNumber",
@Query("plateNumber") plateNumber: String
): ApiResponse<EquipmentUserInfo>
/**
* 获取人脸增量数据
*
* @param timeDate 时间戳(毫秒级)
*/
// @GET//("/shuwei-zhct/scales/getHeartbeatInterface")
// suspend fun getHeartbeatInterface(
// @Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/scales/getHeartbeatInterface",
// @Query("timeDate") timeDate: Long
// ): ApiResponse<List<UserFaceModel>>
/**
* 获取人脸增量数据
*/
@POST
suspend fun getFaceIncrementList(
@Url url:String = "${GlobalData.appBaseUrl}/terminal/neglect/common/app/faceFeature/increment/list",
@Body param:Map<String, Long>
): ApiResponse<List<UserFaceModel>?>
/**
* 获取设备配置数据
*/
@GET
suspend fun getDeviceConfig(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/common/app/getYxEquipmentByEquipmentCode"
): ApiResponse<DeviceConfig?>
} }
@@ -2,6 +2,7 @@ package com.sw.platecabinet.network.interceptor
import com.sw.inbound.utils.SPUtil import com.sw.inbound.utils.SPUtil
import com.sw.plate.App import com.sw.plate.App
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.GlobalKey import com.sw.platecabinet.GlobalKey
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
@@ -16,7 +17,10 @@ class RequestInterceptor : Interceptor {
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Accept", "application/json") .header("Accept", "application/json")
// .header("Authorization", "Bearer ${getToken()}") // .header("Authorization", "Bearer ${getToken()}")
.header("Authorization", getToken()) // .header("Authorization", getToken())
.header("X-Access-Token", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYW50ZWVuSWQiOiJiZTE1NDgzMS0zNDY2LTNiYTItYTJlYS01NzY1MmM5MTlmZWQiLCJ0eXBlIjoiNCIsInVzZXJJZCI6IjAwMDAwMDAwMDAwMDAwMDAwMDEifQ.sN40cOC-O5WQFrF4IDUs8fFlkNdUKLbJt_rHyTsgYYM")
.header("X-DEVICE-CODE", GlobalData.deviceId)
.header("authorization", "57ee87183f2a4fa59683ec9ef41c8f5d")
val newRequest = requestBuilder.build() val newRequest = requestBuilder.build()
@@ -0,0 +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
//
// 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()
// }
// }
// }
}
}
@@ -0,0 +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
// }
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)
}
}
@@ -0,0 +1,21 @@
package com.sw.platecabinet.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.sw.platecabinet.activity.DeviceInitActivity
import com.sw.platecabinet.activity.LoginByFaceActivity
import timber.log.Timber
class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
Timber.d("设备启动完成,开始执行自启动逻辑")
// val intent = Intent(context, LoginByFaceActivity::class.java)
val intent = Intent(context, DeviceInitActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
}
}
@@ -1,6 +1,8 @@
package com.sw.platecabinet.repository package com.sw.platecabinet.repository
import com.google.gson.JsonParseException import com.google.gson.JsonParseException
import com.sw.inbound.utils.GsonUtils
import com.sw.platecabinet.model.CodeMsg
import com.sw.platecabinet.model.response.ApiResponse import com.sw.platecabinet.model.response.ApiResponse
import retrofit2.HttpException import retrofit2.HttpException
import timber.log.Timber import timber.log.Timber
@@ -18,31 +20,37 @@ abstract class BaseRepository {
when (e) { when (e) {
is HttpException -> { is HttpException -> {
ApiResponse(code = e.code(), msg = e.message()) val jsonData = e.response()?.errorBody()?.string()
val codeMsg = GsonUtils.fromJson(jsonData, CodeMsg::class.java)
if (codeMsg?.msg.isNullOrBlank()) {
ApiResponse(code = "" + e.code(), msg = e.message())
} else {
ApiResponse(code = codeMsg?.code?:"", msg = codeMsg?.msg?:"")
}
} }
is SocketTimeoutException -> { is SocketTimeoutException -> {
ApiResponse(code = -2, msg = "请求超时: ${e.message}") ApiResponse(code = "-2", msg = "请求超时: ${e.message}")
} }
is ConnectException -> { is ConnectException -> {
ApiResponse(code = -3, msg = "连接失败: ${e.message}") ApiResponse(code = "-3", msg = "连接失败: ${e.message}")
} }
is SSLHandshakeException -> { is SSLHandshakeException -> {
ApiResponse(code = -4, msg = "SSL握手失败: ${e.message}") ApiResponse(code = "-4", msg = "SSL握手失败: ${e.message}")
} }
is JsonParseException -> { is JsonParseException -> {
ApiResponse(code = -5, msg = "JSON解析错误: ${e.message}") ApiResponse(code = "-5", msg = "JSON解析错误: ${e.message}")
} }
is IOException -> { is IOException -> {
ApiResponse(code = -6, msg = "网络IO错误: ${e.message}") ApiResponse(code = "-6", msg = "网络IO错误: ${e.message}")
} }
else -> { else -> {
ApiResponse(code = -1, msg = "未知错误: ${e.message ?: "无错误信息"}") ApiResponse(code = "-1", msg = "未知错误: ${e.message ?: "无错误信息"}")
} }
} }
} }
@@ -1,11 +1,13 @@
package com.sw.platecabinet.repository package com.sw.platecabinet.repository
import com.sw.platecabinet.GlobalData import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.model.DeviceConfig
import com.sw.platecabinet.model.request.BindParam import com.sw.platecabinet.model.request.BindParam
import com.sw.platecabinet.model.request.EquipmentParam import com.sw.platecabinet.model.request.EquipmentParam
import com.sw.platecabinet.model.request.LoginParam import com.sw.platecabinet.model.request.LoginParam
import com.sw.platecabinet.model.request.SearchParam import com.sw.platecabinet.model.request.SearchParam
import com.sw.platecabinet.model.response.ApiResponse import com.sw.platecabinet.model.response.ApiResponse
import com.sw.platecabinet.model.response.EquipmentInfo
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.model.response.UserFaceModel
@@ -17,27 +19,56 @@ import com.sw.platecabinet.network.api.ApiService
class RemoteRepository constructor( class RemoteRepository constructor(
private val apiService: ApiService private val apiService: ApiService
) : BaseRepository() { ) : BaseRepository() {
/**
* 生成token // /**
*/ // * 生成token
suspend fun generateToken(deviceId: String): ApiResponse<String> { // */
return safeApiCall { // suspend fun getDeviceToken(qrcodeId: String): ApiResponse<String> {
apiService.generateToken( // return safeApiCall {
deviceId, // apiService.getDeviceToken(
GlobalData.appVersion, // qrcodeId
GlobalData.globalEquipmentCode // )
) // }
} // }
} //
// /**
// * 获取设备信息
// */
// suspend fun getDeviceInfo(equipmentCode: String, token: String): ApiResponse<EquipmentInfo> {
// return safeApiCall {
// apiService.getDeviceInfo(
// equipmentCode,
// token = token
// )
// }
// }
//
// /**
// * 生成token
// */
// suspend fun generateToken(deviceId: String): ApiResponse<String> {
// return safeApiCall {
// apiService.generateToken(
// deviceId = deviceId,
// appVersion = GlobalData.appVersion,
// equipmentCode = GlobalData.globalEquipmentCode
// )
// }
// }
/** /**
* 获取人脸数据 * 获取人脸数据
*/ */
suspend fun getUserFaceCache(): ApiResponse<List<UserFaceModel>> { suspend fun getUserFaceCache(
pageNum: Int,
pageSize: Int = 100,
): ApiResponse<List<UserFaceModel>> {
return safeApiCall { return safeApiCall {
apiService.getUserFaceCache( apiService.getUserFaceCache(
GlobalData.appVersion, param = mapOf(
GlobalData.globalEquipmentCode "pageNum" to pageNum,
"pageSize" to pageSize
)
) )
} }
} }
@@ -46,34 +77,71 @@ class RemoteRepository constructor(
* 登录 * 登录
*/ */
suspend fun equipmentBoxLogin(param: LoginParam): ApiResponse<EquipmentUserInfo> { suspend fun equipmentBoxLogin(param: LoginParam): ApiResponse<EquipmentUserInfo> {
return safeApiCall { apiService.equipmentBoxLogin(param) } return safeApiCall { apiService.equipmentBoxLogin(param = param) }
} }
/** /**
* 获取设备绑定用户列表 * 获取设备绑定用户列表
*/ */
suspend fun getEquipmentList(param: EquipmentParam): ApiResponse<List<EquipmentUserInfo>> { suspend fun getEquipmentList(): ApiResponse<List<EquipmentUserInfo>> {
return safeApiCall { apiService.getEquipmentList(param) } return safeApiCall { apiService.getEquipmentList() }
} }
/** // /**
* 餐盘用户信息绑定解绑 // * 餐盘用户信息绑定解绑
*/ // */
suspend fun bindEquipment(param: BindParam): ApiResponse<EquipmentUserInfo?> { // suspend fun bindEquipment(param: BindParam): ApiResponse<EquipmentUserInfo?> {
return safeApiCall { apiService.bindEquipment(param) } // return safeApiCall { apiService.bindEquipment(param = param) }
// }
suspend fun plateBind(param: BindParam): ApiResponse<EquipmentUserInfo?> {
return safeApiCall { apiService.plateBind(param = param) }
}
suspend fun plateUnbind(id: Long?): ApiResponse<Any?> {
return safeApiCall { apiService.plateUnbind(id = id) }
} }
/** /**
* 用户信息模糊搜索 * 用户信息模糊搜索
*/ */
suspend fun searchUser(param: SearchParam): ApiResponse<SearchResult> { suspend fun searchUser(param: SearchParam): ApiResponse<List<SearchResult.Member>?> {
return safeApiCall { apiService.searchUser(param) } return safeApiCall { apiService.searchUser(param = param) }
} }
/** /**
* 通过餐盘编号获取绑定信息 * 通过餐盘编号获取绑定信息
*/ */
suspend fun findByPlateNumber(param: BindParam): ApiResponse<EquipmentUserInfo> { suspend fun findByPlateNumber(plateNumber: String): ApiResponse<EquipmentUserInfo> {
return safeApiCall { apiService.findByPlateNumber(param) } return safeApiCall { apiService.findByPlateNumber(plateNumber = plateNumber) }
}
/**
* 获取人脸增量数据
*
* @param timeDate 时间戳(毫秒级)
*/
// suspend fun getHeartbeatInterface(timeDate: Long): ApiResponse<List<UserFaceModel>> {
// return safeApiCall { apiService.getHeartbeatInterface(timeDate = timeDate) }
// }
suspend fun getFaceIncrementList(
pageNum: Long,
pageSize: Long = 100L,
timestamp: Long
): ApiResponse<List<UserFaceModel>?> {
return safeApiCall {
apiService.getFaceIncrementList(
param = mapOf(
"pageNum" to pageNum,
"pageSize" to pageSize,
"timestamp" to timestamp
)
)
}
}
suspend fun getDeviceConfig(): ApiResponse<DeviceConfig?> {
return safeApiCall { apiService.getDeviceConfig() }
} }
} }
@@ -0,0 +1,66 @@
package com.sw.platecabinet.utils
import kotlinx.coroutines.*
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
class IntervalExecutor {
/**
* 启动定时任务
* @param delayMillis 延迟时间(毫秒)
* @param action 要执行的方法
* @return Job 可用于取消任务
*/
fun startIntervalTask(delayMillis: Long, action: suspend () -> Unit): Job {
return CoroutineScope(Dispatchers.Default).launch {
while (isActive) {
action()
delay(delayMillis)
}
}
}
/**
* 启动定时任务(带初始延迟)
* @param initialDelay 初始延迟时间(毫秒)
* @param delayMillis 后续执行间隔(毫秒)
* @param action 要执行的方法
* @return Job 可用于取消任务
*/
fun startIntervalTaskWithInitialDelay(
initialDelay: Long,
delayMillis: Long,
action: suspend () -> Unit
): Job {
return CoroutineScope(Dispatchers.Default).launch {
delay(initialDelay)
while (isActive) {
action()
delay(delayMillis)
}
}
}
}
// 使用示例
fun main() = runBlocking {
val executor = IntervalExecutor()
// 示例1:每隔10秒执行一次
val job1 = executor.startIntervalTask(10000) {
println("定时任务执行: ${System.currentTimeMillis()}")
// 这里可以执行你的业务逻辑
}
// 示例2:先延迟5秒,然后每隔3秒执行一次
val job2 = executor.startIntervalTaskWithInitialDelay(5000, 3000) {
println("带初始延迟的定时任务: ${System.currentTimeMillis()}")
}
// 运行30秒后取消任务
delay(30000)
job1.cancel()
job2.cancel()
println("所有定时任务已取消")
}
@@ -0,0 +1,103 @@
package com.sw.platecabinet.utils
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
import com.google.zxing.common.BitMatrix
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import kotlin.apply
import kotlin.ranges.until
import kotlin.text.isEmpty
/**
* 二维码生成工具类
*/
object QRCodeUtil {
/**
* 生成二维码(默认大小)
* @param content 二维码内容
* @return 生成的二维码Bitmap
*/
@JvmOverloads
fun generateQRCode(content: String, size: Int = 500): Bitmap? {
return generateQRCode(content, size, Color.BLACK, Color.WHITE)
}
/**
* 生成二维码(自定义颜色)
* @param content 二维码内容
* @param size 二维码边长(像素)
* @param colorCode 二维码颜色
* @param backgroundColor 背景颜色
* @return 生成的二维码Bitmap
*/
fun generateQRCode(
content: String,
size: Int,
colorCode: Int,
backgroundColor: Int
): Bitmap? {
if (content.isEmpty()) {
return null
}
return try {
val hints = mutableMapOf<EncodeHintType, Any>().apply {
put(EncodeHintType.CHARACTER_SET, "UTF-8")
put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H) // 纠错级别
put(EncodeHintType.MARGIN, 1) // 边距
}
val bitMatrix = QRCodeWriter().encode(
content,
BarcodeFormat.QR_CODE,
size,
size,
hints
)
val pixels = IntArray(size * size).apply {
for (y in 0 until size) {
for (x in 0 until size) {
this[y * size + x] = if (bitMatrix.get(x, y)) colorCode else backgroundColor
}
}
}
Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply {
setPixels(pixels, 0, size, 0, 0, size, size)
}
} catch (e: WriterException) {
e.printStackTrace()
null
}
}
/**
* 生成带Logo的二维码
* @param content 二维码内容
* @param size 二维码边长(像素)
* @param logo Logo Bitmap
* @return 带Logo的二维码Bitmap
*/
fun generateQRCodeWithLogo(content: String, size: Int, logo: Bitmap?): Bitmap? {
val qrCode = generateQRCode(content, size) ?: return null
logo ?: return qrCode
val logoSize = size / 5 // Logo大小约为二维码的1/5
val scaledLogo = Bitmap.createScaledBitmap(logo, logoSize, logoSize, false)
val offset = (size - logoSize) / 2
return Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply {
val canvas = Canvas(this)
canvas.drawBitmap(qrCode, 0f, 0f, null)
canvas.drawBitmap(scaledLogo, offset.toFloat(), offset.toFloat(), null)
}
}
}
@@ -0,0 +1,20 @@
package com.sw.platecabinet.utils;
import com.sw.inbound.utils.SPUtil;
import com.sw.platecabinet.MyApp;
public class SpTool {
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);
}
public static void setLastFaceTimestamp(long timestamp) {
SPUtil.Companion.getInstance(MyApp.getContext(), "default_sp").put(LAST_FACE_TIMESTAMP, timestamp);
}
}
@@ -10,6 +10,9 @@ import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
/**
* 加载进度弹窗
*/
public class CustomLoadingDialog extends Dialog { public class CustomLoadingDialog extends Dialog {
@@ -3,7 +3,9 @@ package com.sw.platecabinet.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.model.response.ApiResponse import com.sw.platecabinet.model.response.ApiResponse
import com.sw.platecabinet.model.response.EquipmentInfo
import com.sw.platecabinet.network.ApiClient import com.sw.platecabinet.network.ApiClient
import com.sw.platecabinet.repository.RemoteRepository import com.sw.platecabinet.repository.RemoteRepository
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -62,4 +64,13 @@ abstract class BaseViewModel() : ViewModel() {
fun handleError(exception: Exception) { fun handleError(exception: Exception) {
Timber.d("handleError ${exception.message}") Timber.d("handleError ${exception.message}")
} }
fun parseEquipmentInfo(equipmentInfo: EquipmentInfo) {
// GlobalData.appBaseUrl = equipmentInfo.appPackageUrl!!
// GlobalData.appBaseUrl="https://vip.shuziweidao.com"
// GlobalData.sdkKey = equipmentInfo.arcsoftSdkKey!!
// GlobalData.appId = equipmentInfo.arcsoftAppId!!
// GlobalData.activeKey = equipmentInfo.arcsoftActiveKey!!
// GlobalData.restId = equipmentInfo.canteenId!!
}
} }
@@ -0,0 +1,68 @@
//package com.sw.platecabinet.viewmodel
//
//import com.sw.inbound.utils.GsonUtils
//import com.sw.inbound.utils.SPUtil
//import com.sw.platecabinet.GlobalData
//import com.sw.platecabinet.GlobalKey
//import com.sw.platecabinet.model.response.EquipmentInfo
//import kotlinx.coroutines.flow.MutableStateFlow
//import kotlinx.coroutines.flow.StateFlow
//import timber.log.Timber
//import kotlin.jvm.java
//
///**
// * 初始化的viewmodel
// */
//class DeviceViewModel : BaseViewModel() {
// private val _deviceInfoResult = MutableStateFlow<Boolean?>(null)
// val deviceInfoResult: StateFlow<Boolean?> = _deviceInfoResult
//
// /**
// * 获取token
// */
// fun getDeviceToken(deviceId: String = GlobalData.deviceId) {
// launchWithLoading {
// val response = repository.getDeviceToken(deviceId)
// if (parseResponse(response)) {
// val response1 = repository.getDeviceInfo(deviceId, response.result!!)
//
// if (parseResponse(response1)) {
// val equipmentInfo = response1.result
// if (equipmentInfo == null) return@launchWithLoading
// try {
// parseEquipmentInfo(equipmentInfo)
// SPUtil.getInstance()
// .put(GlobalKey.KEY_EQUIPMENT_INFO, GsonUtils.toJson(equipmentInfo))
// _deviceInfoResult.value = true
// } catch (e: Exception) {
// Timber.e(e)
// }
// }
// }
// }
// }
//
// /**
// * 检查缓存数据
// */
// fun checkEquipmentInfo(): Boolean {
// val equipmentInfoStr = SPUtil.getInstance().get(GlobalKey.KEY_EQUIPMENT_INFO, "")
// if (equipmentInfoStr == null) {
// Timber.e("获取缓存设备信息失败")
// return false
// }
// val equipmentInfo =
// GsonUtils.fromJson<EquipmentInfo>(equipmentInfoStr, EquipmentInfo::class.java)
// if (equipmentInfo == null) {
// Timber.e("解析缓存设备信息失败")
// return false
// }
// try {
// parseEquipmentInfo(equipmentInfo)
// return true
// } catch (e: Exception) {
// Timber.e(e)
// return false
// }
// }
//}
@@ -1,5 +1,6 @@
package com.sw.platecabinet.viewmodel package com.sw.platecabinet.viewmodel
import android.text.TextUtils
import com.sw.inbound.utils.DateTimeUtils import com.sw.inbound.utils.DateTimeUtils
import com.sw.platecabinet.GlobalData import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.GlobalData.globalEquipmentCode import com.sw.platecabinet.GlobalData.globalEquipmentCode
@@ -9,13 +10,21 @@ import com.sw.platecabinet.model.request.EquipmentParam
import com.sw.platecabinet.model.request.SearchParam import com.sw.platecabinet.model.request.SearchParam
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.model.response.UserFaceModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
/**
* 管理员操作viewmodel
*/
class SettingViewModel : BaseViewModel() { class SettingViewModel : BaseViewModel() {
// 设备绑定列表 // 设备绑定列表
private val _equipmentList = MutableStateFlow<List<EquipmentUserInfo>>(emptyList()) // private val _equipmentList = MutableStateFlow<List<EquipmentUserInfo>>(emptyList())
val equipmentList: StateFlow<List<EquipmentUserInfo>> = _equipmentList // val equipmentList: StateFlow<List<EquipmentUserInfo>> = _equipmentList
private val _searchMemberList = MutableStateFlow<List<SearchResult.Member>>(emptyList()) private val _searchMemberList = MutableStateFlow<List<SearchResult.Member>>(emptyList())
val searchMemberList: StateFlow<List<SearchResult.Member>> = _searchMemberList val searchMemberList: StateFlow<List<SearchResult.Member>> = _searchMemberList
@@ -30,105 +39,151 @@ class SettingViewModel : BaseViewModel() {
/** /**
* 绑定/解绑状态 <绑定/解绑, 错误信息,> * 绑定/解绑状态 <绑定/解绑, 错误信息,>
*/ */
private val _bindStateChange = MutableStateFlow<Pair<Boolean?, ErrorInfo>>(null to ErrorInfo()) // private val _bindStateChange = MutableStateFlow<Pair<Boolean?, ErrorInfo>>(null to ErrorInfo())
val bindStateChange: StateFlow<Pair<Boolean?, ErrorInfo>> = _bindStateChange // val bindStateChange: StateFlow<Pair<Boolean?, ErrorInfo>> = _bindStateChange
/** /**
* 获取设备绑定用户信息列表 * 获取设备绑定用户信息列表
*/ */
fun getEquipmentList(equipmentCode: String = globalEquipmentCode) { // fun getEquipmentList(equipmentCode: String = globalEquipmentCode) {
// launchWithLoading {
// val param =
// EquipmentParam(appVersion = GlobalData.appVersion, equipmentCode = equipmentCode)
// val response = repository.getEquipmentList(param)
// if (parseResponse(response)) {
// _equipmentList.value = response.data ?: emptyList()
// }
// }
//// val list = mutableListOf<EquipmentUserInfo>()
//// for (i in 1 .. 30){
//// list.add(EquipmentUserInfo(id = i, equipmentBoxCode = i.toString()))
//// }
//// _equipmentList.value = list
// }
fun getEquipmentList(block: (List<EquipmentUserInfo>) -> Unit) {
launchWithLoading { launchWithLoading {
val param = val response = repository.getEquipmentList()
EquipmentParam(appVersion = GlobalData.appVersion, equipmentCode = equipmentCode)
val response = repository.getEquipmentList(param)
if (parseResponse(response)) { if (parseResponse(response)) {
_equipmentList.value = response.data ?: emptyList() val list = response.data ?: emptyList()
block(list)
} }
} }
// val list = mutableListOf<EquipmentUserInfo>()
// for (i in 1 .. 30){
// list.add(EquipmentUserInfo(id = i, equipmentBoxCode = i.toString()))
// }
// _equipmentList.value = list
} }
/** /**
* 搜索会员信息列表 * 搜索会员信息列表
*/ */
fun getSearchMemberList(param: String, pageNum: Int = 1, pageSize: Int = 50) { fun getSearchMemberList(param:String, pageNum: Int = 1, pageSize: Int = 50) {
if (TextUtils.isEmpty(param)) return
currentPage = pageNum currentPage = pageNum
var name =""
var phone =""
val num = param.toIntOrNull()
if (num != null) {
phone = param
} else {
name = param
}
launch { launch {
val param = SearchParam( val searchParam = SearchParam(
appVersion = GlobalData.appVersion, // appVersion = GlobalData.appVersion,
param = param, name = name,
phone = phone,
pageNum = pageNum, pageNum = pageNum,
pageSize = pageSize pageSize = pageSize
) )
isLoading = true isLoading = true
val response = repository.searchUser(param) val response = repository.searchUser(searchParam)
isLoading = false isLoading = false
if (parseResponse(response)) { if (parseResponse(response)) {
response.data?.let { response.data?.let { list ->
canLoadMore = it.hasNextPage != false
val newList = it.list ?: emptyList()
if (pageNum == 1) { if (pageNum == 1) {
_searchMemberList.value = newList _searchMemberList.value = list
} else { } else {
_searchMemberList.value = _searchMemberList.value.plus(newList) _searchMemberList.value = _searchMemberList.value.plus(list)
} }
currentPage++ if (list.size >= pageSize) currentPage++
} }
} }
} }
} }
fun bindPlate( // fun bindPlate(
equipmentBoxCode: String, // equipmentBoxCode: String,
equipmentCode: String = globalEquipmentCode, // equipmentCode: String = globalEquipmentCode,
memberId: Int, // memberId: Int,
plateNumber: String // plateNumber: String
) { // ) {
_bindStateChange.value = null to ErrorInfo() // _bindStateChange.value = null to ErrorInfo()
// launchWithLoading {
// val bindParam = BindParam(
// appVersion = GlobalData.appVersion,
// equipmentBoxCode = equipmentBoxCode,
// equipmentCode = equipmentCode,
// memberId = memberId,
// plateNumber = plateNumber
// )
// val response = repository.bindEquipment(bindParam)
// if (parseResponse(response)) {
// 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())
// }
// }
// }
// fun unbindPlate(
// equipmentBoxCode: String,
// equipmentCode: String = globalEquipmentCode
// ) {
// launchWithLoading {
// val bindParam = BindParam(
// appVersion = GlobalData.appVersion,
// equipmentBoxCode = equipmentBoxCode,
// equipmentCode = equipmentCode
// )
// val response = repository.bindEquipment(bindParam)
// if (parseResponse(response)) {
// _bindStateChange.value = false to ErrorInfo()
// } else {
// _bindStateChange.value = false to ErrorInfo(response.code, response.msg.toString())
// }
// }
// }
fun unbindPlate(id: Long?, block:(Pair<Boolean?, ErrorInfo>)-> Unit) {
block(null to ErrorInfo())
launchWithLoading { launchWithLoading {
val bindParam = BindParam( val response = repository.plateUnbind(id)
appVersion = GlobalData.appVersion, if (parseResponse(response)) {
equipmentBoxCode = equipmentBoxCode, block(false to ErrorInfo())
equipmentCode = equipmentCode, } else {
memberId = memberId, block(false to ErrorInfo(response.code, response.msg.toString()))
plateNumber = plateNumber }
) }
val response = repository.bindEquipment(bindParam) }
fun bindPlate(bindParam: BindParam, block:(Pair<Boolean?, ErrorInfo>)-> Unit) {
launchWithLoading {
val response = repository.plateBind(bindParam)
if (parseResponse(response)) { if (parseResponse(response)) {
var userInfo = response.data var userInfo = response.data
if (userInfo == null) { if (userInfo == null) {
userInfo = EquipmentUserInfo() userInfo = EquipmentUserInfo()
userInfo.equipmentBoxCode = equipmentBoxCode userInfo.equipmentBoxCode = bindParam.equipmentBoxCode
userInfo.plateNumber = plateNumber userInfo.plateNumber = bindParam.plateNumber
userInfo.equipmentCode = equipmentCode userInfo.equipmentCode = bindParam.equipmentCode
} }
_bindStateChange.value = true to ErrorInfo(equipmentUserInfo = userInfo) block(true to ErrorInfo(equipmentUserInfo = userInfo))
} else { } else {
_bindStateChange.value = true to ErrorInfo(response.code, response.msg.toString()) block(true to ErrorInfo(response.code, response.msg.toString()))
}
}
}
fun unbindPlate(
equipmentBoxCode: String,
equipmentCode: String = globalEquipmentCode
) {
launchWithLoading {
val bindParam = BindParam(
appVersion = GlobalData.appVersion,
equipmentBoxCode = equipmentBoxCode,
equipmentCode = equipmentCode
)
val response = repository.bindEquipment(bindParam)
if (parseResponse(response)) {
_bindStateChange.value = false to ErrorInfo()
} else {
_bindStateChange.value = false to ErrorInfo(response.code, response.msg.toString())
} }
} }
} }
@@ -139,13 +194,9 @@ class SettingViewModel : BaseViewModel() {
) { ) {
_searchUserInfo.value = null _searchUserInfo.value = null
launchWithLoading { launchWithLoading {
val bindParam = BindParam( // val bindParam = BindParam(plateNumber = plateNumber)
appVersion = GlobalData.appVersion, val response = repository.findByPlateNumber(plateNumber)
plateNumber = plateNumber, if (response.code == "00000") {
equipmentCode = equipmentCode
)
val response = repository.findByPlateNumber(bindParam)
if (response.code == 200) {
_searchUserInfo.value = response.data _searchUserInfo.value = response.data
} else { } else {
_searchUserInfo.value = EquipmentUserInfo( _searchUserInfo.value = EquipmentUserInfo(
@@ -156,4 +207,31 @@ class SettingViewModel : BaseViewModel() {
} }
} }
} }
val PAGE_SIZE = 100
/**
* 获取人脸数据
*/
fun getFaceIncrementList(
pageNo: Int = 1,
pageSize: Int = PAGE_SIZE,
timestamp: Long,
block: (List<UserFaceModel>) -> Unit
) {
launch {
val response = repository.getFaceIncrementList(
pageNum = pageNo.toLong(),
pageSize = pageSize.toLong(),
timestamp = timestamp
)
if (parseResponse(response)) {
withContext(Dispatchers.Default) {
val list: List<UserFaceModel> = response.data ?: emptyList()
block(list)
}
}
}
}
} }
@@ -11,9 +11,11 @@ import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.platecabinet.GlobalData import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.GlobalData.globalEquipmentCode import com.sw.platecabinet.GlobalData.globalEquipmentCode
import com.sw.platecabinet.GlobalKey import com.sw.platecabinet.GlobalKey
import com.sw.platecabinet.model.DeviceConfig
import com.sw.platecabinet.model.request.LoginParam import com.sw.platecabinet.model.request.LoginParam
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.model.response.UserFaceModel
import com.sw.platecabinet.utils.SpTool
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -21,7 +23,15 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
/**
* 用户viewmodel
*/
class UserViewModel : BaseViewModel() { class UserViewModel : BaseViewModel() {
companion object {
const val PAGE_SIZE = 100
}
// 通过人脸获取到的用户信息 // 通过人脸获取到的用户信息
private val _currentUserInfo = MutableStateFlow<EquipmentUserInfo?>(null) private val _currentUserInfo = MutableStateFlow<EquipmentUserInfo?>(null)
val currentUserInfo: StateFlow<EquipmentUserInfo?> = _currentUserInfo val currentUserInfo: StateFlow<EquipmentUserInfo?> = _currentUserInfo
@@ -31,40 +41,56 @@ class UserViewModel : BaseViewModel() {
/** /**
* 获取token * 获取token
*/ */
fun generateToken(deviceId: String = "SWSN:88:12:AC:4E:D9:CC") { // fun generateToken(deviceId: String = "SWSN:88:12:AC:4E:D9:CC") {
// launchWithLoading {
// val response = repository.generateToken(deviceId)
// if (parseResponse(response)) {
// // 缓存token
// SPUtil.getInstance().put(GlobalKey.KEY_TOKEN, response.data)
// // 首次运行获取人脸数据
// if (SPUtil.getInstance().get(GlobalKey.KEY_FIRST_RUN, false) != true) {
// getUserFaceCache()
// }
// }
// }
// }
/**
* 获取人脸数据
*/
fun getUserFaceCache(pageNo: Int = 1, pageSize: Int = PAGE_SIZE) {
var currentPageNo = pageNo
launchWithLoading { launchWithLoading {
val response = repository.generateToken(deviceId) val response = repository.getUserFaceCache(pageNum = pageNo, pageSize = pageSize)
if (parseResponse(response)) { if (parseResponse(response)) {
// 缓存token // 获取成功一次后缓存状态
SPUtil.getInstance().put(GlobalKey.KEY_TOKEN, response.data) SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true)
// 首次运行获取人脸数据 val list: List<UserFaceModel> = response.data ?: emptyList()
if (SPUtil.getInstance().get(GlobalKey.KEY_FIRST_RUN, false) != true) { if (pageNo==1&&list.isEmpty()) {
getUserFaceCache() return@launchWithLoading
}
val faceEntityList = list.map {
FaceEntity(it.userId, null, Base64.decode(it.faceFeatureStr))
}
withContext(Dispatchers.Default) {
faceApi.updateFaceData(pageNo, faceEntityList)
if (list.size >= pageSize) {
faceTimestamp = list.last().faceUpdateTimestamp?:0
currentPageNo++
getUserFaceCache(currentPageNo)
return@withContext
}
if (list.isNotEmpty()) {
faceTimestamp = list.last().faceUpdateTimestamp?:0
}
SpTool.setLastFaceTimestamp(faceTimestamp)
//activeEngine()
} }
} }
} }
} }
/** private var faceTimestamp = 0L
* 获取人脸数据
*/
fun getUserFaceCache(index: Int = 0) {
launchWithLoading {
val response = repository.getUserFaceCache()
if (parseResponse(response)) {
// 获取成功一次后缓存状态
SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true)
val list: List<UserFaceModel> = response.data ?: emptyList()
val faceEntity = list.map {
FaceEntity(it.userId, null, Base64.decode(it.faceFeatureString))
}
withContext(Dispatchers.Default) {
faceApi.updateFaceData(index, faceEntity)
activeEngine()
}
}
}
}
/** /**
* 激活人脸识别引擎 * 激活人脸识别引擎
@@ -109,14 +135,8 @@ class UserViewModel : BaseViewModel() {
/** /**
* 校验码登录 * 校验码登录
*/ */
fun loginWithPwd(equipmentCode: String = globalEquipmentCode, phone: String, password: String) { fun loginWithPwd(loginParam: LoginParam) {
launchWithLoading { launchWithLoading {
val loginParam = LoginParam(
appVersion = GlobalData.appVersion,
equipmentCode = equipmentCode,
phone = phone,
password = password
)
val response = repository.equipmentBoxLogin(loginParam) val response = repository.equipmentBoxLogin(loginParam)
if (parseResponse(response)) { if (parseResponse(response)) {
_currentUserInfo.value = response.data _currentUserInfo.value = response.data
@@ -127,17 +147,14 @@ class UserViewModel : BaseViewModel() {
/** /**
* 通过用户id获取用户信息 * 通过用户id获取用户信息
*/ */
fun getUserInfoById(equipmentCode: String = globalEquipmentCode, memberId: Int) { fun getUserInfoById(memberId: String?, action:(EquipmentUserInfo?)->Unit={}) {
_currentUserInfo.value = null _currentUserInfo.value = null
launchWithLoading { launchWithLoading {
val loginParam = LoginParam( val loginParam = LoginParam(faceId = memberId)
appVersion = GlobalData.appVersion,
equipmentCode = equipmentCode,
memberId = memberId
)
val response = repository.equipmentBoxLogin(loginParam) val response = repository.equipmentBoxLogin(loginParam)
if (parseResponse(response)) { if (parseResponse(response)) {
_currentUserInfo.value = response.data _currentUserInfo.value = response.data
action(response.data)
} }
} }
} }
@@ -149,5 +166,16 @@ class UserViewModel : BaseViewModel() {
Timber.d("resetUserInfo") Timber.d("resetUserInfo")
_currentUserInfo.value = null _currentUserInfo.value = null
} }
fun getDeviceConfig(block: (DeviceConfig?) -> Unit) {
// Timber.tag(TAG).d("getDeviceConfig")
launch {
val response = repository.getDeviceConfig()
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
} }
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item>
<shape android:shape="rectangle">
<solid android:color="#ff08C6DC" />
<corners android:radius="8dp" />
</shape>
</item>
</ripple>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="600dp"
android:height="1024dp">
<bitmap android:src="@drawable/bg"/>
</item>
<item
android:width="337dp"
android:height="322dp"
android:gravity="top|center_horizontal"
android:top="112dp">
<bitmap android:src="@drawable/img_init" android:scaleType="fitCenter"/>
</item>
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 999 KiB

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="337dp"
android:layout_height="322dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="112dp"
android:src="@drawable/img_init"
tools:ignore="ContentDescription"
android:visibility="invisible"/>
<TextView
android:id="@+id/btnInit"
android:layout_width="225dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="75dp"
android:background="@drawable/bg_init_button"
android:gravity="center"
android:padding="10dp"
android:text="设备初始化"
android:textColor="@color/white"
android:textSize="22sp"
android:textStyle="bold"
android:visibility="invisible"
tools:ignore="HardcodedText" />
<Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:id="@+id/ivQrCode"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="37dp"
tools:ignore="ContentDescription"
tools:src="@mipmap/ic_logo512"
android:visibility="invisible"/>
</LinearLayout>
+33 -10
View File
@@ -12,29 +12,52 @@
android:id="@+id/includeHeader" android:id="@+id/includeHeader"
layout="@layout/item_title_time" /> layout="@layout/item_title_time" />
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"/>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="260dp" android:layout_marginTop="0dp"
android:gravity="center_horizontal" android:gravity="center"
android:orientation="vertical"> android:orientation="vertical">
<ImageView <ImageView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="142dp"
android:src="@drawable/ic_init_text" /> android:src="@drawable/ic_init_text"
android:adjustViewBounds="true"/>
<ImageView <ImageView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="345dp"
android:layout_marginTop="90dp" android:layout_marginTop="90dp"
android:src="@drawable/ic_init_img" /> android:src="@drawable/ic_init_img"
android:adjustViewBounds="true" />
<ImageView <!-- <ImageView-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginTop="20dp"-->
<!-- android:src="@drawable/ic_init_press" />-->
<TextView android:id="@+id/takeButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="60dp"
android:layout_marginTop="20dp" android:text="点击取盘"
android:src="@drawable/ic_init_press" /> android:textColor="#FFCC99"
android:textSize="24sp"
android:paddingHorizontal="45dp"
android:gravity="center"
android:background="@drawable/btn_outline"
tools:ignore="HardcodedText" />
</LinearLayout> </LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout> </LinearLayout>
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dialogContainer"
android:layout_width="480dp"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="0dp"
android:background="@drawable/bg_dialog"
android:gravity="center"
android:orientation="vertical"
tools:ignore="HardcodedText">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:src="@drawable/ic_tip_warn_unbind" />
<TextView
android:id="@+id/tv_tip_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="余额不足"
android:textColor="#ffffffff"
android:textSize="28sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="请通过小程序或到柜台充值后使用"
android:textColor="#ff999999"
android:textSize="24sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="30dp"
android:background="#ff333333" />
<TextView
android:id="@+id/tv_confirm"
android:layout_width="match_parent"
android:layout_height="90dp"
android:gravity="center"
android:text="知道了"
android:textColor="#ffffcc99"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dialogContainer"
android:layout_width="480dp"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="0dp"
android:background="@drawable/bg_dialog"
android:gravity="center"
android:orientation="vertical"
tools:ignore="HardcodedText">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:src="@drawable/ic_tip_warn_unbind" />
<TextView
android:id="@+id/tv_tip_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="温馨提示"
android:textColor="#ffffffff"
android:textSize="28sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvBindContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="请通过小程序或到柜台充值后使用"
android:textColor="#ff999999"
android:textSize="24sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="30dp"
android:background="#ff333333" />
<TextView
android:id="@+id/tv_confirm"
android:layout_width="match_parent"
android:layout_height="90dp"
android:gravity="center"
android:text="知道了"
android:textColor="#ffffcc99"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
@@ -7,7 +7,8 @@
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:orientation="vertical" android:orientation="vertical"
android:paddingHorizontal="60dp" android:paddingHorizontal="60dp"
tools:context=".fragment.BindPlateFragment"> tools:context=".fragment.BindPlateFragment"
tools:background="@color/black">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -13,7 +13,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="80dp" android:layout_marginTop="80dp"
android:src="@drawable/ic_unbind_img" /> android:rotation="180"
android:src="@drawable/ic_bind_img" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
+3 -4
View File
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="40dp"
android:paddingHorizontal="24dp"> android:paddingHorizontal="24dp">
<TextView <TextView
@@ -11,11 +11,10 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingTop="20dp"
android:textColor="#FFCC99" android:textColor="#FFCC99"
android:textSize="18sp" android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
tools:text="2025年6月18日 星期三" /> tools:text="2025年6月18日 星期三" />
<TextView <TextView
@@ -23,11 +22,11 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingTop="20dp"
android:textColor="#FFCC99" android:textColor="#FFCC99"
android:textSize="18sp" android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvLeftDate" app:layout_constraintTop_toTopOf="@id/tvLeftDate"
app:layout_constraintBottom_toBottomOf="@id/tvLeftDate"
tools:text="14:02:39" /> tools:text="14:02:39" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+1
View File
@@ -3,5 +3,6 @@
<style name="Base.Theme.SmartPlateCabinet" parent="Theme.Material3.DayNight.NoActionBar"> <style name="Base.Theme.SmartPlateCabinet" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. --> <!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> --> <!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
<item name="android:windowBackground">@drawable/bg_splash</item>
</style> </style>
</resources> </resources>
+9 -8
View File
@@ -4,6 +4,7 @@
<item name="android:windowFullscreen">true</item> <item name="android:windowFullscreen">true</item>
<item name="android:windowTranslucentStatus">false</item> <item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item> <item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowBackground">@drawable/bg_splash</item>
</style> </style>
<style name="Theme.SmartPlateCabinet" parent="Base.Theme.SmartPlateCabinet" /> <style name="Theme.SmartPlateCabinet" parent="Base.Theme.SmartPlateCabinet" />
@@ -22,14 +23,14 @@
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
</style> </style>
<style name="DialogActivityTheme" parent="Theme.AppCompat.Dialog"> <style name="DialogActivity" parent="Theme.AppCompat.Light.Dialog">
<item name="windowActionBar">false</item> <item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:windowFrame">@null</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<!--取消默认的居中--> <item name="android:windowIsFloating">true</item>
<item name="android:windowIsFloating">false</item> <item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">#BF000000</item> <item name="android:windowContentOverlay">@null</item>
<item name="android:windowFullscreen">true</item> <item name="android:backgroundDimEnabled">true</item>
<!--触摸外部关闭-->
<item name="android:windowCloseOnTouchOutside">false</item>
</style> </style>
</resources> </resources>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- <domain-config cleartextTrafficPermitted="true">-->
<!-- <domain includeSubdomains="true">vip.shuziweidao.com</domain>-->
<!-- <domain includeSubdomains="true">192.168.1.207</domain>-->
<!-- <domain includeSubdomains="true">device.shuziweidao.com</domain>-->
<!-- </domain-config>-->
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
BIN
View File
Binary file not shown.
+5
View File
@@ -23,7 +23,12 @@ timber = "5.0.1"
gson = "2.13.1" gson = "2.13.1"
hiltAndroid = "2.56.2" hiltAndroid = "2.56.2"
core = "3.4.1"
androidCore = "3.3.0"
[libraries] [libraries]
android-core = { module = "com.google.zxing:android-core", version.ref = "androidCore" }
core = { module = "com.google.zxing:core", version.ref = "core" }
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" } androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" } androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" }
+1 -1
View File
@@ -55,7 +55,7 @@ dependencies {
implementation("com.licheedev:android-serialport:2.1.5") implementation("com.licheedev:android-serialport:2.1.5")
val roomVersion = "2.2.5" val roomVersion = "2.2.5"
implementation("androidx.room:room-runtime:$roomVersion") api("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion") annotationProcessor("androidx.room:room-compiler:$roomVersion")
implementation("io.reactivex.rxjava2:rxandroid:2.0.1") implementation("io.reactivex.rxjava2:rxandroid:2.0.1")
@@ -44,6 +44,18 @@ public class PrefUtils {
sp.edit().putInt(key, value).commit(); sp.edit().putInt(key, value).commit();
} }
public static long getLong(Context ctx, String key, long defaultValue) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
return sp.getLong(key, defaultValue);
}
public static void setLong(Context ctx, String key, long value) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
sp.edit().putLong(key, value).commit();
}
public static float getFloat(Context ctx, String key, float defaultValue) { public static float getFloat(Context ctx, String key, float defaultValue) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
@@ -1,6 +1,7 @@
package com.sw.plate.utils.arcface; package com.sw.plate.utils.arcface;
import android.content.Context; import android.content.Context;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arcsoft.face.FaceEngine; import com.arcsoft.face.FaceEngine;
@@ -32,7 +33,7 @@ public class FaceApi {
public void updateFaceData(int index, List<FaceEntity> list) { public void updateFaceData(int index, List<FaceEntity> list) {
Log.d(TAG, "updateFaceData: index = " + index + ", listSize = " + list.size()); Log.d(TAG, "updateFaceData: index = " + index + ", listSize = " + list.size());
FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao(); FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao();
if (index == 0) { if (index == 1) {
faceDao.deleteAll(); faceDao.deleteAll();
faceDao.resetId(); faceDao.resetId();
} }
@@ -79,4 +80,26 @@ public class FaceApi {
// List<FacePreviewInfo> facePreviewInfoList = recognizeViewModel.onPreviewFrame(nv21, true); // List<FacePreviewInfo> facePreviewInfoList = recognizeViewModel.onPreviewFrame(nv21, true);
return null; return null;
} }
public void deleteByUserName(String userName) {
FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao();
faceDao.deleteFaceById(userName);
}
public Long insert(FaceEntity entity) {
if (entity == null) {
return 0L;
}
FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao();
return faceDao.insert(entity);
}
public FaceEntity queryByUserName(String userName) {
if (TextUtils.isEmpty(userName)) {
return null;
}
FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao();
return faceDao.queryByUserName(userName);
}
} }
@@ -88,4 +88,7 @@ public interface FaceDao {
@Query("UPDATE sqlite_sequence SET seq = 0 WHERE name ='face'") @Query("UPDATE sqlite_sequence SET seq = 0 WHERE name ='face'")
void resetId(); void resetId();
@Query("SELECT * FROM face WHERE user_name = :userName limit 1")
FaceEntity queryByUserName(String userName);
} }
@@ -2,9 +2,11 @@ package com.sw.plate.utils.arcface.facedb.entity;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.text.TextUtils;
import androidx.room.ColumnInfo; import androidx.room.ColumnInfo;
import androidx.room.Entity; import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import java.util.Arrays; import java.util.Arrays;
@@ -42,7 +44,14 @@ public class FaceEntity implements Parcelable {
*/ */
@ColumnInfo(name = "register_time") @ColumnInfo(name = "register_time")
private long registerTime; private long registerTime;
/**
* 用户类型:1-普通会员、2-临时用户、3-内部员工、或者其它待定类型
*/
@ColumnInfo(name = "user_type")
private String userType;
@Ignore
private int trackId;//人脸追踪ID
public FaceEntity(String userName, String imagePath, byte[] featureData) { public FaceEntity(String userName, String imagePath, byte[] featureData) {
this.userName = userName; this.userName = userName;
@@ -120,6 +129,22 @@ public class FaceEntity implements Parcelable {
this.registerTime = registerTime; this.registerTime = registerTime;
} }
public int getTrackId() {
return trackId;
}
public void setTrackId(int trackId) {
this.trackId = trackId;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
@@ -132,8 +157,11 @@ public class FaceEntity implements Parcelable {
dest.writeString(userName); dest.writeString(userName);
dest.writeString(imagePath); dest.writeString(imagePath);
dest.writeByteArray(featureData); dest.writeByteArray(featureData);
dest.writeString(userType);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@@ -143,16 +171,17 @@ public class FaceEntity implements Parcelable {
return false; return false;
} }
FaceEntity that = (FaceEntity) o; FaceEntity that = (FaceEntity) o;
return faceId == that.faceId && return this.faceId == that.faceId &&
registerTime == that.registerTime && this.registerTime == that.registerTime &&
userName.equals(that.userName) && TextUtils.equals(this.userName, that.userName) &&
imagePath.equals(that.imagePath) && TextUtils.equals(this.imagePath, that.imagePath) &&
Arrays.equals(featureData, that.featureData); Arrays.equals(featureData, that.featureData) &&
TextUtils.equals(this.userType, that.userType);
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = Objects.hash(faceId, registerTime, userName, imagePath); int result = Objects.hash(faceId, registerTime, userName, imagePath, userType);
result = 31 * result + Arrays.hashCode(featureData); result = 31 * result + Arrays.hashCode(featureData);
return result; return result;
} }
@@ -33,6 +33,7 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -60,6 +61,10 @@ public class FaceServer {
faceRegisterInfoList = new ArrayList<>(); faceRegisterInfoList = new ArrayList<>();
} }
public FaceEngine getFaceEngine() {
return faceEngine;
}
public static FaceServer getInstance() { public static FaceServer getInstance() {
if (faceServer == null) { if (faceServer == null) {
synchronized (FaceServer.class) { synchronized (FaceServer.class) {
@@ -341,6 +346,7 @@ public class FaceServer {
*/ */
public void registerFaceFeatureInfoFromDb(FaceEntity faceEntity, FaceEngine faceEngine) { public void registerFaceFeatureInfoFromDb(FaceEntity faceEntity, FaceEngine faceEngine) {
if (faceEntity != null && faceEngine != null) { if (faceEntity != null && faceEngine != null) {
Log.i(TAG, "registerFaceFeature:" + faceEntity.getFaceId()+"==="+ Arrays.toString(faceEntity.getFeatureData()));
FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo((int) faceEntity.getFaceId(), faceEntity.getFeatureData()); FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo((int) faceEntity.getFaceId(), faceEntity.getFeatureData());
int res = faceEngine.registerFaceFeature(faceFeatureInfo); int res = faceEngine.registerFaceFeature(faceFeatureInfo);
Log.i(TAG, "registerFaceFeature:" + res); Log.i(TAG, "registerFaceFeature:" + res);
@@ -337,8 +337,10 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
} }
public void addFace(FaceEntity faceEntity) { public void addFace(FaceEntity faceEntity) {
if (frEngine != null) if (frEngine != null) {
Log.e("performSync", "addFace=" + faceEntity.getRegisterTime());
FaceServer.getInstance().registerFaceFeatureInfoFromDb(faceEntity, frEngine); FaceServer.getInstance().registerFaceFeatureInfoFromDb(faceEntity, frEngine);
}
} }
public void refreshFaceList() { public void refreshFaceList() {