清理人脸识别代码;清理所有编译警告
This commit is contained in:
@@ -131,7 +131,6 @@ dependencies {
|
|||||||
implementation("androidx.camera:camera-view:$cameraXVersion")
|
implementation("androidx.camera:camera-view:$cameraXVersion")
|
||||||
|
|
||||||
implementation("com.google.zxing:core:3.5.4")
|
implementation("com.google.zxing:core:3.5.4")
|
||||||
implementation("com.google.mlkit:face-detection:16.1.7")
|
|
||||||
implementation("com.aliyun.dpa:oss-android-sdk:2.9.21")
|
implementation("com.aliyun.dpa:oss-android-sdk:2.9.21")
|
||||||
implementation("com.aliyun:ocr_api20210707:3.1.3") {
|
implementation("com.aliyun:ocr_api20210707:3.1.3") {
|
||||||
exclude(group = "pull-parser", module = "pull-parser")
|
exclude(group = "pull-parser", module = "pull-parser")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.bbitcn.f8.pad.base
|
package com.bbitcn.f8.pad.base
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.AnimatedVisibilityScope
|
import androidx.compose.animation.AnimatedVisibilityScope
|
||||||
@@ -25,6 +26,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
@@ -54,11 +56,10 @@ import androidx.compose.material3.InputChipDefaults
|
|||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.ScrollableTabRow
|
import androidx.compose.material3.PrimaryTabRow
|
||||||
|
import androidx.compose.material3.SecondaryScrollableTabRow
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.material3.TabRow
|
|
||||||
import androidx.compose.material3.TabRowDefaults
|
import androidx.compose.material3.TabRowDefaults
|
||||||
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.VerticalDivider
|
import androidx.compose.material3.VerticalDivider
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -71,6 +72,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
@@ -95,6 +97,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
import com.bbitcn.f8.pad.M
|
import com.bbitcn.f8.pad.M
|
||||||
|
import com.bbitcn.f8.pad.MyApp
|
||||||
import com.bbitcn.f8.pad.R
|
import com.bbitcn.f8.pad.R
|
||||||
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
||||||
import com.bbitcn.f8.pad.ui.screen.view.drawer.IconInfo
|
import com.bbitcn.f8.pad.ui.screen.view.drawer.IconInfo
|
||||||
@@ -355,24 +358,18 @@ fun VipBadgePreview() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun VipBadge(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
|
fun VipBadge(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
|
||||||
Box(modifier = modifier) {
|
Box(modifier = modifier) {
|
||||||
// 内容显示区域
|
|
||||||
content()
|
content()
|
||||||
|
|
||||||
// 显示 Badge
|
Image(
|
||||||
Box(
|
painter = painterResource(id = R.drawable.vip),
|
||||||
modifier = M
|
contentDescription = null,
|
||||||
.align(Alignment.TopEnd) // 控制Badge的位置
|
contentScale = ContentScale.Fit,
|
||||||
.padding(2.5.dp) // 适当的内边距,避免和内容重叠
|
modifier = Modifier
|
||||||
) {
|
.align(Alignment.TopEnd)
|
||||||
// Badge(containerColor = MyColors.Transparent) {
|
.offset(x = 7.dp, y = (-7).dp)
|
||||||
Image(
|
.size(18.dp)
|
||||||
painter = painterResource(id = R.drawable.vip),
|
.alpha(0.82f)
|
||||||
contentDescription = null,
|
)
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
modifier = Modifier.size(20.dp)
|
|
||||||
)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,7 +779,8 @@ fun isLandscape(): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isBluetoothEnabled(): Boolean {
|
fun isBluetoothEnabled(): Boolean {
|
||||||
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
|
val bluetoothManager = MyApp.appContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
||||||
|
val bluetoothAdapter = bluetoothManager.adapter
|
||||||
return bluetoothAdapter?.isEnabled == true
|
return bluetoothAdapter?.isEnabled == true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,11 +807,11 @@ fun MyTabRowHorizontal(
|
|||||||
) {
|
) {
|
||||||
var curPage by rememberSaveable { mutableStateOf(0) }
|
var curPage by rememberSaveable { mutableStateOf(0) }
|
||||||
Column {
|
Column {
|
||||||
TabRow(
|
PrimaryTabRow(
|
||||||
selectedTabIndex = curPage,
|
selectedTabIndex = curPage,
|
||||||
indicator = { tabPositions ->
|
indicator = {
|
||||||
TabRowDefaults.Indicator(
|
TabRowDefaults.PrimaryIndicator(
|
||||||
M.tabIndicatorOffset(tabPositions[curPage]),
|
M.tabIndicatorOffset(curPage),
|
||||||
color = MyColors.BlueGreen
|
color = MyColors.BlueGreen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -880,14 +878,14 @@ fun MyScrollableTabRow(
|
|||||||
tabs: List<String>,
|
tabs: List<String>,
|
||||||
onValueChange: (Int) -> Unit = {}
|
onValueChange: (Int) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
ScrollableTabRow(
|
SecondaryScrollableTabRow(
|
||||||
selectedTabIndex = position,
|
selectedTabIndex = position,
|
||||||
containerColor = MyColors.Transparent,
|
containerColor = MyColors.Transparent,
|
||||||
edgePadding = 5.dp,
|
edgePadding = 5.dp,
|
||||||
modifier = moidifer,
|
modifier = moidifer,
|
||||||
indicator = { tabPositions ->
|
indicator = {
|
||||||
TabRowDefaults.SecondaryIndicator(
|
TabRowDefaults.SecondaryIndicator(
|
||||||
M.tabIndicatorOffset(tabPositions[position]),
|
M.tabIndicatorOffset(position),
|
||||||
color = MyColors.BlueGreen,
|
color = MyColors.BlueGreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ data class FaceRecognizeResponse(
|
|||||||
@SerializedName("log_id")
|
@SerializedName("log_id")
|
||||||
val logId: Long = 0,
|
val logId: Long = 0,
|
||||||
@SerializedName("result")
|
@SerializedName("result")
|
||||||
val result: Result = Result(),
|
val result: Result? = Result(),
|
||||||
@SerializedName("timestamp")
|
@SerializedName("timestamp")
|
||||||
val timestamp: Long = 0
|
val timestamp: Long = 0
|
||||||
) {
|
) {
|
||||||
@@ -33,4 +33,4 @@ data class FaceRecognizeResponse(
|
|||||||
val userInfo: String = ""
|
val userInfo: String = ""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
package com.bbitcn.f8.pad.receiver
|
package com.bbitcn.f8.pad.receiver
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
@@ -5,14 +7,17 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.wifi.WifiInfo
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.os.BatteryManager
|
import android.os.BatteryManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.telephony.PhoneStateListener
|
import android.telephony.PhoneStateListener
|
||||||
import android.telephony.SignalStrength
|
import android.telephony.SignalStrength
|
||||||
|
import android.telephony.TelephonyCallback
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.core.content.ContextCompat
|
||||||
import com.bbitcn.f8.pad.utils.PollingTask
|
import com.bbitcn.f8.pad.utils.PollingTask
|
||||||
import com.bbitcn.f8.pad.utils.log.MyLog
|
import com.bbitcn.f8.pad.utils.log.MyLog
|
||||||
import com.bbitcn.f8.pad.utils.registerReceiverCompat
|
import com.bbitcn.f8.pad.utils.registerReceiverCompat
|
||||||
@@ -29,16 +34,43 @@ class SystemInfoReceiver(private val context: Context) {
|
|||||||
|
|
||||||
private val _signalStrength = MutableStateFlow(0)
|
private val _signalStrength = MutableStateFlow(0)
|
||||||
val signalStrength = _signalStrength.asStateFlow()
|
val signalStrength = _signalStrength.asStateFlow()
|
||||||
|
|
||||||
|
private val connectivityManager =
|
||||||
|
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
private val telephonyManager =
|
||||||
|
context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 信号强度监听器
|
* 信号强度监听器
|
||||||
*/
|
*/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
private val networkStateListener = object : PhoneStateListener() {
|
private val networkStateListener = object : PhoneStateListener() {
|
||||||
|
@Deprecated("Only used for Android 11 compatibility.")
|
||||||
override fun onSignalStrengthsChanged(signalStrengths: SignalStrength) {
|
override fun onSignalStrengthsChanged(signalStrengths: SignalStrength) {
|
||||||
super.onSignalStrengthsChanged(signalStrengths)
|
super.onSignalStrengthsChanged(signalStrengths)
|
||||||
_signalStrength.value = signalStrengths.level
|
_signalStrength.value = signalStrengths.level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var telephonyCallback: TelephonyCallback? = null
|
||||||
|
|
||||||
|
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||||
|
override fun onAvailable(network: Network) {
|
||||||
|
refreshNetworkStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCapabilitiesChanged(
|
||||||
|
network: Network,
|
||||||
|
networkCapabilities: NetworkCapabilities
|
||||||
|
) {
|
||||||
|
updateNetworkStatus(networkCapabilities)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLost(network: Network) {
|
||||||
|
refreshNetworkStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val batteryReceiver = object : BroadcastReceiver() {
|
private val batteryReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(ctx: Context?, intent: Intent?) {
|
override fun onReceive(ctx: Context?, intent: Intent?) {
|
||||||
val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
|
val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
|
||||||
@@ -46,54 +78,17 @@ class SystemInfoReceiver(private val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val connectivityReceiver = object : BroadcastReceiver() {
|
|
||||||
override fun onReceive(ctx: Context?, intent: Intent?) {
|
|
||||||
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
||||||
val activeNetwork = connectivityManager.activeNetwork
|
|
||||||
val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
|
|
||||||
|
|
||||||
networkCapabilities?.let {
|
|
||||||
when {
|
|
||||||
it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
|
|
||||||
_networkType.value = "WIFI"
|
|
||||||
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
|
||||||
val wifiInfo = wifiManager.connectionInfo
|
|
||||||
_signalStrength.value = WifiManager.calculateSignalLevel(wifiInfo.rssi, 5)
|
|
||||||
}
|
|
||||||
it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
|
|
||||||
_networkType.value = "Cellular"
|
|
||||||
val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
|
||||||
telephonyManager.listen(networkStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)
|
|
||||||
}
|
|
||||||
it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
|
|
||||||
_networkType.value = "Ethernet"
|
|
||||||
_signalStrength.value = 4 // Ethernet typically has a strong connection
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
_networkType.value = "Unknown"
|
|
||||||
_signalStrength.value = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
_networkType.value = "No Connection"
|
|
||||||
_signalStrength.value = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun register() {
|
fun register() {
|
||||||
val batteryIntentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
val batteryIntentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
||||||
val connectivityIntentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
|
|
||||||
|
|
||||||
context.registerReceiverCompat(
|
context.registerReceiverCompat(
|
||||||
batteryReceiver,
|
batteryReceiver,
|
||||||
batteryIntentFilter
|
batteryIntentFilter
|
||||||
)
|
)
|
||||||
|
|
||||||
context.registerReceiverCompat(
|
connectivityManager.registerDefaultNetworkCallback(networkCallback)
|
||||||
connectivityReceiver,
|
registerSignalStrengthListener()
|
||||||
connectivityIntentFilter
|
refreshNetworkStatus()
|
||||||
)
|
|
||||||
// 开始轮询网络状态 防止状态假死
|
// 开始轮询网络状态 防止状态假死
|
||||||
PollingTask.getInstance("SystemInfoReceiver").startPollingTaskOnIOThread("NetworkStatusPolling",30_000) {
|
PollingTask.getInstance("SystemInfoReceiver").startPollingTaskOnIOThread("NetworkStatusPolling",30_000) {
|
||||||
refreshNetworkStatus()
|
refreshNetworkStatus()
|
||||||
@@ -102,42 +97,106 @@ class SystemInfoReceiver(private val context: Context) {
|
|||||||
|
|
||||||
fun unregister() {
|
fun unregister() {
|
||||||
context.unregisterReceiver(batteryReceiver)
|
context.unregisterReceiver(batteryReceiver)
|
||||||
context.unregisterReceiver(connectivityReceiver)
|
runCatching {
|
||||||
|
connectivityManager.unregisterNetworkCallback(networkCallback)
|
||||||
|
}.onFailure {
|
||||||
|
MyLog.appError("取消网络监听失败:${it.message}")
|
||||||
|
}
|
||||||
|
unregisterSignalStrengthListener()
|
||||||
PollingTask.getInstance("SystemInfoReceiver").stopTask("NetworkStatusPolling")
|
PollingTask.getInstance("SystemInfoReceiver").stopTask("NetworkStatusPolling")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshNetworkStatus() {
|
private fun refreshNetworkStatus() {
|
||||||
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
||||||
val activeNetwork = connectivityManager.activeNetwork
|
val activeNetwork = connectivityManager.activeNetwork
|
||||||
val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
|
val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
|
||||||
|
|
||||||
networkCapabilities?.let {
|
if (networkCapabilities == null) {
|
||||||
when {
|
|
||||||
it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
|
|
||||||
_networkType.value = "WIFI"
|
|
||||||
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
|
||||||
val wifiInfo = wifiManager.connectionInfo
|
|
||||||
val rssi = wifiInfo.rssi
|
|
||||||
if (rssi != -127) { // -127 通常是无效值
|
|
||||||
_signalStrength.value = WifiManager.calculateSignalLevel(rssi, 5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
|
|
||||||
_networkType.value = "Cellular"
|
|
||||||
// 通常需要 TelephonyManager.getSignalStrength,但这里只能靠原来 listener 补充
|
|
||||||
}
|
|
||||||
it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
|
|
||||||
_networkType.value = "Ethernet"
|
|
||||||
_signalStrength.value = 4
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
_networkType.value = "Unknown"
|
|
||||||
_signalStrength.value = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
_networkType.value = "No Connection"
|
_networkType.value = "No Connection"
|
||||||
_signalStrength.value = 0
|
_signalStrength.value = 0
|
||||||
|
} else {
|
||||||
|
updateNetworkStatus(networkCapabilities)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateNetworkStatus(networkCapabilities: NetworkCapabilities) {
|
||||||
|
when {
|
||||||
|
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
|
||||||
|
_networkType.value = "WIFI"
|
||||||
|
updateWifiSignalStrength(networkCapabilities)
|
||||||
|
}
|
||||||
|
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
|
||||||
|
_networkType.value = "Cellular"
|
||||||
|
}
|
||||||
|
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
|
||||||
|
_networkType.value = "Ethernet"
|
||||||
|
_signalStrength.value = 4
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
_networkType.value = "Unknown"
|
||||||
|
_signalStrength.value = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateWifiSignalStrength(networkCapabilities: NetworkCapabilities) {
|
||||||
|
val rssi = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
(networkCapabilities.transportInfo as? WifiInfo)?.rssi
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||||
|
wifiManager.connectionInfo?.rssi
|
||||||
|
}
|
||||||
|
if (rssi != null && rssi != -127) {
|
||||||
|
_signalStrength.value = calculateSignalLevel(rssi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateSignalLevel(rssi: Int): Int {
|
||||||
|
return when {
|
||||||
|
rssi <= -100 -> 0
|
||||||
|
rssi >= -55 -> 4
|
||||||
|
else -> ((rssi + 100) * 4 / 45).coerceIn(0, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerSignalStrengthListener() {
|
||||||
|
runCatching {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
val callback = object : TelephonyCallback(), TelephonyCallback.SignalStrengthsListener {
|
||||||
|
override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
|
||||||
|
_signalStrength.value = signalStrength.level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
telephonyCallback = callback
|
||||||
|
telephonyManager.registerTelephonyCallback(
|
||||||
|
ContextCompat.getMainExecutor(context),
|
||||||
|
callback
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
telephonyManager.listen(
|
||||||
|
networkStateListener,
|
||||||
|
PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
MyLog.appError("注册信号强度监听失败:${it.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unregisterSignalStrengthListener() {
|
||||||
|
runCatching {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
telephonyCallback?.let {
|
||||||
|
telephonyManager.unregisterTelephonyCallback(it)
|
||||||
|
}
|
||||||
|
telephonyCallback = null
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
telephonyManager.listen(networkStateListener, PhoneStateListener.LISTEN_NONE)
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
MyLog.appError("取消信号强度监听失败:${it.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package com.bbitcn.f8.pad.ui
|
package com.bbitcn.f8.pad.ui
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import androidx.activity.OnBackPressedCallback
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.animation.EnterTransition
|
import androidx.compose.animation.EnterTransition
|
||||||
@@ -26,6 +25,9 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
@@ -71,6 +73,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
installSplashScreen()
|
installSplashScreen()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setFullScreen(true)
|
setFullScreen(true)
|
||||||
|
registerBackPressedCallback()
|
||||||
// 初始化NfcAdapter
|
// 初始化NfcAdapter
|
||||||
PrinterBT.init()
|
PrinterBT.init()
|
||||||
WaterCutMeterBT.init()
|
WaterCutMeterBT.init()
|
||||||
@@ -243,30 +246,35 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setFullScreen(isFullScreen: Boolean) {
|
fun setFullScreen(isFullScreen: Boolean) {
|
||||||
|
val controller = WindowCompat.getInsetsController(window, window.decorView)
|
||||||
if (isFullScreen) {
|
if (isFullScreen) {
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
|
controller.systemBarsBehavior =
|
||||||
val decorView = window.decorView
|
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
val uiOptions = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
controller.hide(WindowInsetsCompat.Type.systemBars())
|
||||||
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
||||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
|
||||||
decorView.systemUiVisibility = uiOptions
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
|
WindowCompat.setDecorFitsSystemWindows(window, true)
|
||||||
|
controller.show(WindowInsetsCompat.Type.systemBars())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastBackPressedTime: Long = 0
|
private var lastBackPressedTime: Long = 0
|
||||||
|
|
||||||
override fun onBackPressed() {
|
private fun registerBackPressedCallback() {
|
||||||
val currentTime = System.currentTimeMillis()
|
onBackPressedDispatcher.addCallback(
|
||||||
if (currentTime - lastBackPressedTime < 2000) { // 如果两次点击时间间隔小于2秒
|
this,
|
||||||
super.onBackPressed() // 调用系统默认的退出行为
|
object : OnBackPressedCallback(true) {
|
||||||
} else {
|
override fun handleOnBackPressed() {
|
||||||
Toasty.showToast("再按一次退出")
|
val currentTime = System.currentTimeMillis()
|
||||||
lastBackPressedTime = currentTime
|
if (currentTime - lastBackPressedTime < 2000) {
|
||||||
}
|
finish()
|
||||||
|
} else {
|
||||||
|
Toasty.showToast("再按一次退出")
|
||||||
|
lastBackPressedTime = currentTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.material3.TabRow
|
import androidx.compose.material3.PrimaryTabRow
|
||||||
import androidx.compose.material3.TabRowDefaults
|
import androidx.compose.material3.TabRowDefaults
|
||||||
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
@@ -140,11 +139,11 @@ fun TabPagerScreen(
|
|||||||
val pagerState = rememberPagerState(pageCount = { tabs.size })
|
val pagerState = rememberPagerState(pageCount = { tabs.size })
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
Column {
|
Column {
|
||||||
TabRow(
|
PrimaryTabRow(
|
||||||
selectedTabIndex = pagerState.currentPage,
|
selectedTabIndex = pagerState.currentPage,
|
||||||
indicator = { tabPositions ->
|
indicator = {
|
||||||
TabRowDefaults.Indicator(
|
TabRowDefaults.PrimaryIndicator(
|
||||||
M.tabIndicatorOffset(tabPositions[pagerState.currentPage]),
|
M.tabIndicatorOffset(pagerState.currentPage),
|
||||||
color = MyColors.BlueGreen,
|
color = MyColors.BlueGreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -375,7 +374,7 @@ fun PhoneLogin(loginViewModel: LoginViewModel) {
|
|||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 20.dp)
|
.padding(top = 20.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,7 +397,7 @@ fun FaceLogin(loginViewModel: LoginViewModel) {
|
|||||||
Text(
|
Text(
|
||||||
text = "请保持光线充足,人脸无遮挡",
|
text = "请保持光线充足,人脸无遮挡",
|
||||||
color = MyColors.Gray,
|
color = MyColors.Gray,
|
||||||
modifier = M.padding(vertical = 10.dp)
|
modifier = M.padding(vertical = 2.5.dp)
|
||||||
)
|
)
|
||||||
MyButton(
|
MyButton(
|
||||||
text = "开始识别登录",
|
text = "开始识别登录",
|
||||||
@@ -406,7 +405,7 @@ fun FaceLogin(loginViewModel: LoginViewModel) {
|
|||||||
loginViewModel.faceRecognize()
|
loginViewModel.faceRecognize()
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 5.dp)
|
.padding(top = 20.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import androidx.compose.foundation.Image
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -27,12 +28,11 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.ClickableText
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.Divider
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -54,10 +54,12 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.layout.LastBaseline
|
import androidx.compose.ui.layout.LastBaseline
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
|
import androidx.compose.ui.text.TextLayoutResult
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -324,7 +326,7 @@ private fun AuthorNameTimestamp(msg: Message, isUserMe: Boolean) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RowScope.DayHeaderLine() {
|
private fun RowScope.DayHeaderLine() {
|
||||||
Divider(
|
HorizontalDivider(
|
||||||
modifier = M
|
modifier = M
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.align(Alignment.CenterVertically),
|
.align(Alignment.CenterVertically),
|
||||||
@@ -360,20 +362,28 @@ fun ChatItemBubble(
|
|||||||
text = chatRecord.content,
|
text = chatRecord.content,
|
||||||
primary = isUserMe
|
primary = isUserMe
|
||||||
)
|
)
|
||||||
ClickableText(
|
var textLayoutResult by remember { mutableStateOf<TextLayoutResult?>(null) }
|
||||||
|
Text(
|
||||||
text = styledMessage,
|
text = styledMessage,
|
||||||
style = MaterialTheme.typography.bodyLarge.copy(color = textColor),
|
style = MaterialTheme.typography.bodyLarge.copy(color = textColor),
|
||||||
modifier = M.padding(16.dp),
|
modifier = M
|
||||||
onClick = {
|
.padding(16.dp)
|
||||||
styledMessage
|
.pointerInput(styledMessage) {
|
||||||
.getStringAnnotations(start = it, end = it)
|
detectTapGestures { position ->
|
||||||
.firstOrNull()
|
val offset = textLayoutResult?.getOffsetForPosition(position) ?: return@detectTapGestures
|
||||||
?.let { annotation ->
|
styledMessage
|
||||||
when (annotation.tag) {
|
.getStringAnnotations(start = offset, end = offset)
|
||||||
SymbolAnnotationType.LINK.name -> uriHandler.openUri(annotation.item)
|
.firstOrNull()
|
||||||
else -> Unit
|
?.let { annotation ->
|
||||||
}
|
when (annotation.tag) {
|
||||||
|
SymbolAnnotationType.LINK.name -> uriHandler.openUri(annotation.item)
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onTextLayout = {
|
||||||
|
textLayoutResult = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import androidx.compose.foundation.gestures.detectTapGestures
|
|||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
@@ -51,6 +54,7 @@ fun FaceDialog(
|
|||||||
viewModel: FaceDialogViewModel = viewModel()
|
viewModel: FaceDialogViewModel = viewModel()
|
||||||
) {
|
) {
|
||||||
val tips by viewModel.tips.collectAsState()
|
val tips by viewModel.tips.collectAsState()
|
||||||
|
val countdownSeconds by viewModel.countdownSeconds.collectAsState()
|
||||||
MyDialog("人脸识别-${tips}",
|
MyDialog("人脸识别-${tips}",
|
||||||
info.showDialog,
|
info.showDialog,
|
||||||
onDismissRequest = { info.onDismiss() },
|
onDismissRequest = { info.onDismiss() },
|
||||||
@@ -65,7 +69,11 @@ fun FaceDialog(
|
|||||||
) {
|
) {
|
||||||
LaunchedEffect(info.showDialog) {
|
LaunchedEffect(info.showDialog) {
|
||||||
if (info.showDialog){
|
if (info.showDialog){
|
||||||
viewModel.initializeCamera(info.isRegister,info.isSystemUser){ userId,faceToken->
|
viewModel.initializeCamera(
|
||||||
|
isRegister = info.isRegister,
|
||||||
|
isSystemUser = info.isSystemUser,
|
||||||
|
onAutoCapture = info.onDismiss
|
||||||
|
) { userId,faceToken->
|
||||||
// 识别成功的方法
|
// 识别成功的方法
|
||||||
info.onDismiss()
|
info.onDismiss()
|
||||||
info.onRecognizeFace(userId, faceToken)
|
info.onRecognizeFace(userId, faceToken)
|
||||||
@@ -113,6 +121,24 @@ fun FaceDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (countdownSeconds > 0) {
|
||||||
|
Surface(
|
||||||
|
modifier = M
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
.padding(top = 16.dp),
|
||||||
|
shape = MaterialTheme.shapes.large,
|
||||||
|
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.88f),
|
||||||
|
tonalElevation = 6.dp,
|
||||||
|
shadowElevation = 8.dp
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${countdownSeconds}秒后开始识别",
|
||||||
|
modifier = M.padding(horizontal = 24.dp, vertical = 12.dp),
|
||||||
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
style = MaterialTheme.typography.titleLarge
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,11 @@ import android.hardware.camera2.CameraCharacteristics
|
|||||||
import android.hardware.camera2.CameraManager
|
import android.hardware.camera2.CameraManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.camera.camera2.interop.Camera2CameraInfo
|
import androidx.camera.camera2.interop.Camera2CameraInfo
|
||||||
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
|
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
|
||||||
import androidx.camera.core.Camera
|
import androidx.camera.core.Camera
|
||||||
import androidx.camera.core.CameraSelector
|
import androidx.camera.core.CameraSelector
|
||||||
import androidx.camera.core.ImageAnalysis
|
|
||||||
import androidx.camera.core.ImageCapture
|
import androidx.camera.core.ImageCapture
|
||||||
import androidx.camera.core.ImageCaptureException
|
import androidx.camera.core.ImageCaptureException
|
||||||
import androidx.camera.core.Preview
|
import androidx.camera.core.Preview
|
||||||
@@ -19,6 +17,7 @@ import androidx.camera.core.SurfaceRequest
|
|||||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.alibaba.sdk.android.oss.ClientException
|
import com.alibaba.sdk.android.oss.ClientException
|
||||||
import com.alibaba.sdk.android.oss.ServiceException
|
import com.alibaba.sdk.android.oss.ServiceException
|
||||||
import com.alibaba.sdk.android.oss.model.ObjectMetadata
|
import com.alibaba.sdk.android.oss.model.ObjectMetadata
|
||||||
@@ -31,16 +30,17 @@ import com.bbitcn.f8.pad.model.net.response.FarmerDetailResponse
|
|||||||
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
||||||
import com.bbitcn.f8.pad.ui.screen.view.Toasty.showTipsDialog
|
import com.bbitcn.f8.pad.ui.screen.view.Toasty.showTipsDialog
|
||||||
import com.bbitcn.f8.pad.utils.MMKVUtil
|
import com.bbitcn.f8.pad.utils.MMKVUtil
|
||||||
|
import com.bbitcn.f8.pad.utils.MyUtil
|
||||||
import com.bbitcn.f8.pad.utils.externalModules.devices.reader.face.FaceRecognize
|
import com.bbitcn.f8.pad.utils.externalModules.devices.reader.face.FaceRecognize
|
||||||
import com.bbitcn.f8.pad.utils.externalModules.devices.reader.face.OssUtils
|
import com.bbitcn.f8.pad.utils.externalModules.devices.reader.face.OssUtils
|
||||||
import com.bbitcn.f8.pad.utils.global.RxTag
|
import com.bbitcn.f8.pad.utils.global.RxTag
|
||||||
import com.bbitcn.f8.pad.utils.log.MyLog
|
import com.bbitcn.f8.pad.utils.log.MyLog
|
||||||
import com.google.mlkit.vision.common.InputImage
|
import kotlinx.coroutines.Job
|
||||||
import com.google.mlkit.vision.face.FaceDetection
|
import kotlinx.coroutines.delay
|
||||||
import com.google.mlkit.vision.face.FaceDetectorOptions
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Random
|
import java.util.Random
|
||||||
|
|
||||||
@@ -49,6 +49,8 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
|
|
||||||
private val _tips = MutableStateFlow("")
|
private val _tips = MutableStateFlow("")
|
||||||
val tips = _tips.asStateFlow()
|
val tips = _tips.asStateFlow()
|
||||||
|
private val _countdownSeconds = MutableStateFlow(0)
|
||||||
|
val countdownSeconds = _countdownSeconds.asStateFlow()
|
||||||
private val _surfaceRequests = MutableStateFlow<SurfaceRequest?>(null)
|
private val _surfaceRequests = MutableStateFlow<SurfaceRequest?>(null)
|
||||||
val surfaceRequests: StateFlow<SurfaceRequest?> get() = _surfaceRequests.asStateFlow()
|
val surfaceRequests: StateFlow<SurfaceRequest?> get() = _surfaceRequests.asStateFlow()
|
||||||
|
|
||||||
@@ -66,14 +68,14 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
lateinit var curCameraInfo: CameraInfo
|
lateinit var curCameraInfo: CameraInfo
|
||||||
|
|
||||||
var myCamera: Camera? = null
|
var myCamera: Camera? = null
|
||||||
|
private var autoRecognizeJob: Job? = null
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
context = MyApp.appContext
|
context = MyApp.appContext
|
||||||
lifecycleOwner = context as LifecycleOwner
|
lifecycleOwner = context as LifecycleOwner
|
||||||
// 获取当前设备的旋转角度
|
// 获取当前设备的旋转角度
|
||||||
val rotation = (context.getSystemService(Context.WINDOW_SERVICE) as WindowManager)
|
val rotation = MyUtil.getDisplayRotation(context)
|
||||||
.defaultDisplay.rotation
|
|
||||||
imageCapture = ImageCapture.Builder()
|
imageCapture = ImageCapture.Builder()
|
||||||
.setTargetRotation(rotation)
|
.setTargetRotation(rotation)
|
||||||
.build()
|
.build()
|
||||||
@@ -82,15 +84,20 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
private var _isRegister = false
|
private var _isRegister = false
|
||||||
private var _isSystemUser = false
|
private var _isSystemUser = false
|
||||||
private var _onRecognizeFace: ((userId: String, faceToken: String) -> Unit) = { _, _ -> }
|
private var _onRecognizeFace: ((userId: String, faceToken: String) -> Unit) = { _, _ -> }
|
||||||
|
private var _onAutoCapture: () -> Unit = {}
|
||||||
|
|
||||||
fun initializeCamera(
|
fun initializeCamera(
|
||||||
isRegister: Boolean,
|
isRegister: Boolean,
|
||||||
isSystemUser: Boolean,
|
isSystemUser: Boolean,
|
||||||
|
onAutoCapture: () -> Unit = {},
|
||||||
onRecognizeFace: (userId: String, faceToken: String) -> Unit
|
onRecognizeFace: (userId: String, faceToken: String) -> Unit
|
||||||
) {
|
) {
|
||||||
_isSystemUser = isSystemUser
|
_isSystemUser = isSystemUser
|
||||||
_isRegister = isRegister
|
_isRegister = isRegister
|
||||||
|
_onAutoCapture = onAutoCapture
|
||||||
_onRecognizeFace = onRecognizeFace
|
_onRecognizeFace = onRecognizeFace
|
||||||
|
_tips.value = ""
|
||||||
|
_countdownSeconds.value = 0
|
||||||
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||||
val cameraIdList = cameraManager.cameraIdList
|
val cameraIdList = cameraManager.cameraIdList
|
||||||
|
|
||||||
@@ -132,9 +139,10 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(androidx.camera.core.ExperimentalGetImage::class)
|
|
||||||
fun setCameraSelector(cameraInfo: CameraInfo) {
|
fun setCameraSelector(cameraInfo: CameraInfo) {
|
||||||
MyLog.test("setCameraSelector: ${cameraInfo.cameraId}, ${cameraInfo.lensFacing}")
|
MyLog.test("setCameraSelector: ${cameraInfo.cameraId}, ${cameraInfo.lensFacing}")
|
||||||
|
autoRecognizeJob?.cancel()
|
||||||
|
_showPreview.value = true
|
||||||
// 创建新的 CameraSelector
|
// 创建新的 CameraSelector
|
||||||
cameraSelector = CameraSelector.Builder()
|
cameraSelector = CameraSelector.Builder()
|
||||||
.requireLensFacing(cameraInfo.lensFacing)
|
.requireLensFacing(cameraInfo.lensFacing)
|
||||||
@@ -159,74 +167,43 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
// 解绑所有之前的用例
|
// 解绑所有之前的用例
|
||||||
cameraProvider?.unbindAll()
|
cameraProvider?.unbindAll()
|
||||||
|
|
||||||
val imageAnalysis = ImageAnalysis.Builder()
|
|
||||||
// 默认情况下,ImageAnalysis 的输出图像格式是 YUV,适合用于高效的图像处理和计算,但如果你需要以 RGBA 格式输出图像(通常用于处理图像像素颜色、UI 渲染等),就可以启用这一行代码。
|
|
||||||
// .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
|
|
||||||
// .setTargetResolution(Size(1280, 720))
|
|
||||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
// 高精度人脸检测
|
|
||||||
val highAccuracyOpts = FaceDetectorOptions.Builder()
|
|
||||||
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
|
|
||||||
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
|
|
||||||
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
|
|
||||||
.build()
|
|
||||||
// 实时人脸检测
|
|
||||||
val realTimeOpts = FaceDetectorOptions.Builder()
|
|
||||||
.setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)
|
|
||||||
.build()
|
|
||||||
val detector = FaceDetection.getClient(realTimeOpts)
|
|
||||||
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context)) { imageProxy ->
|
|
||||||
val mediaImage = imageProxy.image
|
|
||||||
if (mediaImage != null) {
|
|
||||||
val image =
|
|
||||||
InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
|
|
||||||
val result = detector.process(image)
|
|
||||||
.addOnSuccessListener { faces ->
|
|
||||||
// MyLog.face("检测到人脸数量: ${faces.size}")
|
|
||||||
if (faces.size == 1) {
|
|
||||||
_showPreview.value = false
|
|
||||||
if (!_isRegister) {
|
|
||||||
// 识别:自动
|
|
||||||
faceRecognize()
|
|
||||||
// 停止分析
|
|
||||||
imageAnalysis.clearAnalyzer()
|
|
||||||
}
|
|
||||||
} else if (faces.size > 1) {
|
|
||||||
_tips.value = "识别到多个人,请重试"
|
|
||||||
} else {
|
|
||||||
_tips.value = "未识别到人脸"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.addOnFailureListener { e ->
|
|
||||||
MyLog.face("没有人脸,${e.message}")
|
|
||||||
}
|
|
||||||
.addOnCompleteListener {
|
|
||||||
mediaImage.close()
|
|
||||||
imageProxy.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 绑定选择的摄像头和预览用例
|
// 绑定选择的摄像头和预览用例
|
||||||
myCamera = cameraProvider?.bindToLifecycle(
|
myCamera = cameraProvider?.bindToLifecycle(
|
||||||
lifecycleOwner,
|
lifecycleOwner,
|
||||||
cameraSelector!!,
|
cameraSelector!!,
|
||||||
imageCapture,
|
imageCapture,
|
||||||
imageAnalysis,
|
|
||||||
previewUseCase!!
|
previewUseCase!!
|
||||||
)
|
)
|
||||||
|
scheduleAutoRecognize()
|
||||||
}, ContextCompat.getMainExecutor(context))
|
}, ContextCompat.getMainExecutor(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun scheduleAutoRecognize() {
|
||||||
|
autoRecognizeJob?.cancel()
|
||||||
|
if (_isRegister) {
|
||||||
|
_countdownSeconds.value = 0
|
||||||
|
_tips.value = "请调整画面后点击确定注册"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
autoRecognizeJob = viewModelScope.launch {
|
||||||
|
for (second in 3 downTo 1) {
|
||||||
|
_countdownSeconds.value = second
|
||||||
|
_tips.value = "${second}秒后自动识别,请保持光线充足,人脸无遮挡"
|
||||||
|
delay(1000L)
|
||||||
|
}
|
||||||
|
_countdownSeconds.value = 0
|
||||||
|
_tips.value = "正在拍照识别"
|
||||||
|
faceRecognize(onPhotoTaken = _onAutoCapture)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun focusOnPoint(surfaceBounds: Size, x: Float, y: Float) {
|
fun focusOnPoint(surfaceBounds: Size, x: Float, y: Float) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun takePicture(onFinish: (Uri) -> Unit = {}) {
|
fun takePicture(onFinish: (Uri) -> Unit = {}) {
|
||||||
val file = File(context.externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
|
val file = MyUtil.createPictureFile(context)
|
||||||
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
|
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
|
||||||
val cameraExecutor = ContextCompat.getMainExecutor(context)
|
val cameraExecutor = ContextCompat.getMainExecutor(context)
|
||||||
imageCapture.takePicture(outputFileOptions, cameraExecutor,
|
imageCapture.takePicture(outputFileOptions, cameraExecutor,
|
||||||
@@ -238,9 +215,9 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
|
|
||||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||||
// Toasty.success("拍照成功")
|
// Toasty.success("拍照成功")
|
||||||
val savedUri = outputFileResults.savedUri
|
val savedUri = outputFileResults.savedUri ?: Uri.fromFile(file)
|
||||||
// _savedUri.value = savedUri
|
// _savedUri.value = savedUri
|
||||||
onFinish(savedUri!!)
|
onFinish(savedUri)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -307,7 +284,7 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++3.上传信息到服务器
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++3.上传信息到服务器
|
||||||
val result3 = apiService.registerFaceForF8(
|
val result3 = apiService.registerFaceForF8(
|
||||||
data = FaceRegisterF8Request(
|
data = FaceRegisterF8Request(
|
||||||
baiduFaceToken = success1!!.result.faceToken,
|
baiduFaceToken = success1.result.faceToken,
|
||||||
ossBucketname = config.bucketName,
|
ossBucketname = config.bucketName,
|
||||||
ossObjectname = objectName,
|
ossObjectname = objectName,
|
||||||
userid = userId,
|
userid = userId,
|
||||||
@@ -333,8 +310,12 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun faceRecognize() {
|
fun faceRecognize(onPhotoTaken: () -> Unit = {}) {
|
||||||
|
autoRecognizeJob?.cancel()
|
||||||
|
_countdownSeconds.value = 0
|
||||||
|
_showPreview.value = false
|
||||||
takePicture {
|
takePicture {
|
||||||
|
onPhotoTaken()
|
||||||
doInIoThreadThenUI("正在识别人脸", onIO = {
|
doInIoThreadThenUI("正在识别人脸", onIO = {
|
||||||
val accessToken = apiService.getFaceAccessToken()
|
val accessToken = apiService.getFaceAccessToken()
|
||||||
val result = FaceRecognize.faceRecognize(
|
val result = FaceRecognize.faceRecognize(
|
||||||
@@ -345,9 +326,11 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
return@doInIoThreadThenUI result
|
return@doInIoThreadThenUI result
|
||||||
}) { result ->
|
}) { result ->
|
||||||
if (result.first == "false") {
|
if (result.first == "false") {
|
||||||
// 重新启动摄像头
|
_tips.value = result.second
|
||||||
setCameraSelector(curCameraInfo)
|
_showPreview.value = true
|
||||||
|
Toasty.error("人脸识别失败:${result.second}")
|
||||||
} else {
|
} else {
|
||||||
|
_tips.value = ""
|
||||||
_onRecognizeFace(result.first, result.second)
|
_onRecognizeFace(result.first, result.second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,4 +358,4 @@ class FaceDialogViewModel : BaseViewModel() {
|
|||||||
return "$prefix-$timestamp-$randomNum."
|
return "$prefix-$timestamp-$randomNum."
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.hardware.camera2.CameraCharacteristics
|
|||||||
import android.hardware.camera2.CameraManager
|
import android.hardware.camera2.CameraManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.camera.camera2.interop.Camera2CameraInfo
|
import androidx.camera.camera2.interop.Camera2CameraInfo
|
||||||
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
|
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
|
||||||
import androidx.camera.core.Camera
|
import androidx.camera.core.Camera
|
||||||
@@ -21,6 +20,7 @@ import com.bbitcn.f8.pad.MyApp
|
|||||||
import com.bbitcn.f8.pad.base.BaseViewModel
|
import com.bbitcn.f8.pad.base.BaseViewModel
|
||||||
import com.bbitcn.f8.pad.ui.screen.secondFunc.CameraInfo
|
import com.bbitcn.f8.pad.ui.screen.secondFunc.CameraInfo
|
||||||
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
||||||
|
import com.bbitcn.f8.pad.utils.MyUtil
|
||||||
import com.bbitcn.f8.pad.utils.log.MyLog
|
import com.bbitcn.f8.pad.utils.log.MyLog
|
||||||
import com.bbitcn.f8.pad.utils.externalModules.ocr.ALiApi
|
import com.bbitcn.f8.pad.utils.externalModules.ocr.ALiApi
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -57,8 +57,7 @@ class OCRDialogViewModel : BaseViewModel() {
|
|||||||
doInIoThreadThenUI("初始化相机", onIO = {
|
doInIoThreadThenUI("初始化相机", onIO = {
|
||||||
lifecycleOwner = context as LifecycleOwner
|
lifecycleOwner = context as LifecycleOwner
|
||||||
// 获取当前设备的旋转角度
|
// 获取当前设备的旋转角度
|
||||||
val rotation = (context.getSystemService(Context.WINDOW_SERVICE) as WindowManager)
|
val rotation = MyUtil.getDisplayRotation(context)
|
||||||
.defaultDisplay.rotation
|
|
||||||
imageCapture = ImageCapture.Builder()
|
imageCapture = ImageCapture.Builder()
|
||||||
.setTargetRotation(rotation)
|
.setTargetRotation(rotation)
|
||||||
.build()
|
.build()
|
||||||
@@ -142,7 +141,7 @@ class OCRDialogViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun takePicture(onFinish: (Uri) -> Unit = {}) {
|
fun takePicture(onFinish: (Uri) -> Unit = {}) {
|
||||||
val file = File(context.externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
|
val file = MyUtil.createPictureFile(context)
|
||||||
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
|
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
|
||||||
val cameraExecutor = ContextCompat.getMainExecutor(context)
|
val cameraExecutor = ContextCompat.getMainExecutor(context)
|
||||||
imageCapture.takePicture(outputFileOptions, cameraExecutor,
|
imageCapture.takePicture(outputFileOptions, cameraExecutor,
|
||||||
@@ -153,10 +152,10 @@ class OCRDialogViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||||
val savedUri = outputFileResults.savedUri
|
val savedUri = outputFileResults.savedUri ?: Uri.fromFile(file)
|
||||||
// 拍照成功后关闭相机
|
// 拍照成功后关闭相机
|
||||||
cameraProvider?.unbindAll()
|
cameraProvider?.unbindAll()
|
||||||
onFinish(savedUri!!)
|
onFinish(savedUri)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -213,4 +212,4 @@ data class CameraInfo(
|
|||||||
val cameraId: String,
|
val cameraId: String,
|
||||||
val lensFacing: Int,
|
val lensFacing: Int,
|
||||||
val cameraName: String
|
val cameraName: String
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -122,7 +122,9 @@ fun FundsScreen(
|
|||||||
val dateStart =
|
val dateStart =
|
||||||
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(start)
|
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(start)
|
||||||
val dateEnd = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(end)
|
val dateEnd = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(end)
|
||||||
fundsViewModel.updateDateRange(dateStart to dateEnd)
|
if (dateStart != null && dateEnd != null) {
|
||||||
|
fundsViewModel.updateDateRange(dateStart to dateEnd)
|
||||||
|
}
|
||||||
onFilterLikeChanged(queryInput)
|
onFilterLikeChanged(queryInput)
|
||||||
}
|
}
|
||||||
DateRangePickTextFiled(M.fillMaxWidth(), dateRange = queryDateRange) {
|
DateRangePickTextFiled(M.fillMaxWidth(), dateRange = queryDateRange) {
|
||||||
|
|||||||
@@ -22,10 +22,9 @@ import androidx.compose.material3.DatePickerDialog
|
|||||||
import androidx.compose.material3.DateRangePicker
|
import androidx.compose.material3.DateRangePicker
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ScrollableTabRow
|
import androidx.compose.material3.SecondaryScrollableTabRow
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.material3.TabRowDefaults
|
import androidx.compose.material3.TabRowDefaults
|
||||||
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.rememberDateRangePickerState
|
import androidx.compose.material3.rememberDateRangePickerState
|
||||||
@@ -147,15 +146,15 @@ fun PurchaseScreen(
|
|||||||
purchaseViewModel.openAddTicketDialog(navController)
|
purchaseViewModel.openAddTicketDialog(navController)
|
||||||
})
|
})
|
||||||
if (isLandscape()) {
|
if (isLandscape()) {
|
||||||
ScrollableTabRow(
|
SecondaryScrollableTabRow(
|
||||||
modifier = M
|
modifier = M
|
||||||
.weight(1f),
|
.weight(1f),
|
||||||
selectedTabIndex = queryType,
|
selectedTabIndex = queryType,
|
||||||
containerColor = MyColors.Transparent,
|
containerColor = MyColors.Transparent,
|
||||||
edgePadding = 10.dp,
|
edgePadding = 10.dp,
|
||||||
indicator = { tabPositions ->
|
indicator = {
|
||||||
TabRowDefaults.SecondaryIndicator(
|
TabRowDefaults.SecondaryIndicator(
|
||||||
M.tabIndicatorOffset(tabPositions[queryType]),
|
M.tabIndicatorOffset(queryType),
|
||||||
color = MyColors.BlueGreen,
|
color = MyColors.BlueGreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -202,14 +201,14 @@ fun PurchaseScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isLandscape()) {
|
if (!isLandscape()) {
|
||||||
ScrollableTabRow(
|
SecondaryScrollableTabRow(
|
||||||
selectedTabIndex = queryType,
|
selectedTabIndex = queryType,
|
||||||
containerColor = MyColors.Transparent,
|
containerColor = MyColors.Transparent,
|
||||||
edgePadding = 0.dp,
|
edgePadding = 0.dp,
|
||||||
modifier = M,
|
modifier = M,
|
||||||
indicator = { tabPositions ->
|
indicator = {
|
||||||
TabRowDefaults.SecondaryIndicator(
|
TabRowDefaults.SecondaryIndicator(
|
||||||
M.tabIndicatorOffset(tabPositions[queryType]),
|
M.tabIndicatorOffset(queryType),
|
||||||
color = MyColors.BlueGreen,
|
color = MyColors.BlueGreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import androidx.compose.runtime.setValue
|
|||||||
import com.alibaba.sdk.android.oss.OSS
|
import com.alibaba.sdk.android.oss.OSS
|
||||||
import com.alibaba.sdk.android.oss.OSSClient
|
import com.alibaba.sdk.android.oss.OSSClient
|
||||||
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider
|
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider
|
||||||
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider
|
|
||||||
import com.alibaba.sdk.android.oss.model.GeneratePresignedUrlRequest
|
import com.alibaba.sdk.android.oss.model.GeneratePresignedUrlRequest
|
||||||
import com.bbitcn.f8.pad.MyApp
|
import com.bbitcn.f8.pad.MyApp
|
||||||
import com.bbitcn.f8.pad.base.BaseViewModel
|
import com.bbitcn.f8.pad.base.BaseViewModel
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.hardware.camera2.CameraCharacteristics
|
|||||||
import android.hardware.camera2.CameraManager
|
import android.hardware.camera2.CameraManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.camera.camera2.interop.Camera2CameraInfo
|
import androidx.camera.camera2.interop.Camera2CameraInfo
|
||||||
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
|
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
|
||||||
import androidx.camera.core.Camera
|
import androidx.camera.core.Camera
|
||||||
@@ -23,6 +22,7 @@ import com.bbitcn.f8.pad.base.BaseViewModel
|
|||||||
import com.bbitcn.f8.pad.ui.screen.dialog.CameraInfo
|
import com.bbitcn.f8.pad.ui.screen.dialog.CameraInfo
|
||||||
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
import com.bbitcn.f8.pad.ui.screen.view.Toasty
|
||||||
import com.bbitcn.f8.pad.utils.MMKVUtil
|
import com.bbitcn.f8.pad.utils.MMKVUtil
|
||||||
|
import com.bbitcn.f8.pad.utils.MyUtil
|
||||||
import com.bbitcn.f8.pad.utils.externalModules.devices.reader.face.FaceRecognize
|
import com.bbitcn.f8.pad.utils.externalModules.devices.reader.face.FaceRecognize
|
||||||
import com.bbitcn.f8.pad.utils.log.MyLog
|
import com.bbitcn.f8.pad.utils.log.MyLog
|
||||||
import com.bbitcn.f8.pad.utils.externalModules.ocr.ALiApi
|
import com.bbitcn.f8.pad.utils.externalModules.ocr.ALiApi
|
||||||
@@ -60,8 +60,7 @@ class MyCameraViewModel : BaseViewModel() {
|
|||||||
context = MyApp.appContext
|
context = MyApp.appContext
|
||||||
lifecycleOwner = context as LifecycleOwner
|
lifecycleOwner = context as LifecycleOwner
|
||||||
// 获取当前设备的旋转角度
|
// 获取当前设备的旋转角度
|
||||||
val rotation = (context.getSystemService(Context.WINDOW_SERVICE) as WindowManager)
|
val rotation = MyUtil.getDisplayRotation(context)
|
||||||
.defaultDisplay.rotation
|
|
||||||
imageCapture = ImageCapture.Builder()
|
imageCapture = ImageCapture.Builder()
|
||||||
.setTargetRotation(rotation)
|
.setTargetRotation(rotation)
|
||||||
.build()
|
.build()
|
||||||
@@ -151,7 +150,7 @@ class MyCameraViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun takePicture(onFinish: (Uri) -> Unit = {}) {
|
fun takePicture(onFinish: (Uri) -> Unit = {}) {
|
||||||
val file = File(context.externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
|
val file = MyUtil.createPictureFile(context)
|
||||||
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
|
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
|
||||||
val cameraExecutor = ContextCompat.getMainExecutor(context)
|
val cameraExecutor = ContextCompat.getMainExecutor(context)
|
||||||
imageCapture.takePicture(outputFileOptions, cameraExecutor,
|
imageCapture.takePicture(outputFileOptions, cameraExecutor,
|
||||||
@@ -163,9 +162,9 @@ class MyCameraViewModel : BaseViewModel() {
|
|||||||
|
|
||||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||||
Toasty.success("拍照成功")
|
Toasty.success("拍照成功")
|
||||||
val savedUri = outputFileResults.savedUri
|
val savedUri = outputFileResults.savedUri ?: Uri.fromFile(file)
|
||||||
_savedUri.value = savedUri
|
_savedUri.value = savedUri
|
||||||
onFinish(savedUri!!)
|
onFinish(savedUri)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -227,4 +226,4 @@ data class CameraInfo(
|
|||||||
val cameraId: String,
|
val cameraId: String,
|
||||||
val lensFacing: Int,
|
val lensFacing: Int,
|
||||||
val cameraName: String
|
val cameraName: String
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.wrapContentHeight
|
|||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -89,14 +88,14 @@ fun PayOperate(modifier: Modifier, payViewModel: PayViewModel) {
|
|||||||
}
|
}
|
||||||
MyCard(border = BorderStroke(1.dp, MyColors.Gray), elevation = 0.dp) {
|
MyCard(border = BorderStroke(1.dp, MyColors.Gray), elevation = 0.dp) {
|
||||||
Column {
|
Column {
|
||||||
ScrollableTabRow(
|
SecondaryScrollableTabRow(
|
||||||
selectedTabIndex = pagerState.currentPage,
|
selectedTabIndex = pagerState.currentPage,
|
||||||
containerColor = MyColors.Transparent,
|
containerColor = MyColors.Transparent,
|
||||||
edgePadding = 10.dp,
|
edgePadding = 10.dp,
|
||||||
modifier = M.wrapContentHeight(),
|
modifier = M.wrapContentHeight(),
|
||||||
indicator = { tabPositions ->
|
indicator = {
|
||||||
TabRowDefaults.SecondaryIndicator(
|
TabRowDefaults.SecondaryIndicator(
|
||||||
M.tabIndicatorOffset(tabPositions[pagerState.currentPage]),
|
M.tabIndicatorOffset(pagerState.currentPage),
|
||||||
color = MyColors.BlueGreen,
|
color = MyColors.BlueGreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -191,14 +190,14 @@ fun WeightList(weightViewModel: WeightViewModel) {
|
|||||||
val detailList by weightViewModel.detailList.collectAsState()
|
val detailList by weightViewModel.detailList.collectAsState()
|
||||||
Column(modifier = M.padding(horizontal = 10.dp)) {
|
Column(modifier = M.padding(horizontal = 10.dp)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
ScrollableTabRow(
|
SecondaryScrollableTabRow(
|
||||||
selectedTabIndex = pagerState.currentPage,
|
selectedTabIndex = pagerState.currentPage,
|
||||||
containerColor = MyColors.Transparent,
|
containerColor = MyColors.Transparent,
|
||||||
modifier = M
|
modifier = M
|
||||||
.weight(1f),
|
.weight(1f),
|
||||||
indicator = { tabPositions ->
|
indicator = {
|
||||||
TabRowDefaults.SecondaryIndicator(
|
TabRowDefaults.SecondaryIndicator(
|
||||||
M.tabIndicatorOffset(tabPositions[pagerState.currentPage]),
|
M.tabIndicatorOffset(pagerState.currentPage),
|
||||||
color = MyColors.BlueGreen,
|
color = MyColors.BlueGreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import com.commandiron.wheel_picker_compose.WheelDateTimePicker
|
|||||||
import com.commandiron.wheel_picker_compose.core.TimeFormat
|
import com.commandiron.wheel_picker_compose.core.TimeFormat
|
||||||
import com.commandiron.wheel_picker_compose.core.WheelPickerDefaults
|
import com.commandiron.wheel_picker_compose.core.WheelPickerDefaults
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@@ -63,7 +63,7 @@ object Toasty : BaseViewModel() {
|
|||||||
val drawerContent: StateFlow<@Composable () -> Unit> = _drawerContent.asStateFlow()
|
val drawerContent: StateFlow<@Composable () -> Unit> = _drawerContent.asStateFlow()
|
||||||
|
|
||||||
fun showOptionDrawer(title: String, options: List<String>, onClick: (String) -> Unit) {
|
fun showOptionDrawer(title: String, options: List<String>, onClick: (String) -> Unit) {
|
||||||
GlobalScope.launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
if (options.isEmpty()) {
|
if (options.isEmpty()) {
|
||||||
Toasty.showToast("暂无选项")
|
Toasty.showToast("暂无选项")
|
||||||
|
|||||||
+6
-6
@@ -215,7 +215,7 @@ fun TicketForDryStoreCocoon(
|
|||||||
"芯片",
|
"芯片",
|
||||||
3,
|
3,
|
||||||
{ if (it.rfid.length >= 6) ".." + it.rfid.takeLast(4) else it.rfid }),
|
{ if (it.rfid.length >= 6) ".." + it.rfid.takeLast(4) else it.rfid }),
|
||||||
MyTableData("状态", 2, { it.status.toString() }),
|
MyTableData("状态", 2, { it.status }),
|
||||||
MyTableData("毛重", 2, { it.maozhong.toString() }),
|
MyTableData("毛重", 2, { it.maozhong.toString() }),
|
||||||
MyTableData("皮重", 2, { it.pizhong.toString() }),
|
MyTableData("皮重", 2, { it.pizhong.toString() }),
|
||||||
MyTableData("净重", 2, { it.jingzhong.toString() }),
|
MyTableData("净重", 2, { it.jingzhong.toString() }),
|
||||||
@@ -231,13 +231,13 @@ fun TicketForDryStoreCocoon(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
InfoText(
|
InfoText(
|
||||||
"乡镇",
|
"乡镇",
|
||||||
it.xiangzhen.toString(),
|
it.xiangzhen,
|
||||||
M.weight(2f),
|
M.weight(2f),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
InfoText(
|
InfoText(
|
||||||
"芯片",
|
"芯片",
|
||||||
it.rfid.toString(),
|
it.rfid,
|
||||||
M.weight(3f),
|
M.weight(3f),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -251,13 +251,13 @@ fun TicketForDryStoreCocoon(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
InfoText(
|
InfoText(
|
||||||
"类型",
|
"类型",
|
||||||
ex.type.toString(),
|
ex.type,
|
||||||
M.weight(2f),
|
M.weight(2f),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
InfoText(
|
InfoText(
|
||||||
"时间",
|
"时间",
|
||||||
ex.time.toString(),
|
ex.time,
|
||||||
M.weight(3f),
|
M.weight(3f),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -265,7 +265,7 @@ fun TicketForDryStoreCocoon(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
InfoText(
|
InfoText(
|
||||||
"备注",
|
"备注",
|
||||||
ex.memo.toString(),
|
ex.memo,
|
||||||
M.weight(3f),
|
M.weight(3f),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ object AudioPlayer {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val nextResId = audioQueue.poll()
|
val nextResId = audioQueue.removeFirst()
|
||||||
val player = MediaPlayer.create(MyApp.appContext, nextResId)
|
val player = MediaPlayer.create(MyApp.appContext, nextResId)
|
||||||
mediaPlayer = player
|
mediaPlayer = player
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.bbitcn.f8.pad.utils
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import com.bbitcn.f8.pad.MyApp.Companion.appContext
|
import com.bbitcn.f8.pad.MyApp.Companion.appContext
|
||||||
import com.bbitcn.f8.pad.utils.global.Global
|
import com.bbitcn.f8.pad.utils.global.Global
|
||||||
@@ -12,6 +14,7 @@ import com.blankj.utilcode.util.EncryptUtils
|
|||||||
import com.google.zxing.BarcodeFormat
|
import com.google.zxing.BarcodeFormat
|
||||||
import com.google.zxing.EncodeHintType
|
import com.google.zxing.EncodeHintType
|
||||||
import com.google.zxing.MultiFormatWriter
|
import com.google.zxing.MultiFormatWriter
|
||||||
|
import java.io.File
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@@ -50,13 +53,30 @@ object MyUtil {
|
|||||||
val packageManager = appContext.packageManager
|
val packageManager = appContext.packageManager
|
||||||
val packageInfo =
|
val packageInfo =
|
||||||
packageManager.getPackageInfo(appContext.packageName, 0)
|
packageManager.getPackageInfo(appContext.packageName, 0)
|
||||||
return packageInfo.versionCode
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
packageInfo.longVersionCode.toInt()
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
packageInfo.versionCode
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDisplayRotation(context: Context = appContext): Int {
|
||||||
|
return context.display.rotation
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createPictureFile(context: Context = appContext): File {
|
||||||
|
val dir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) ?: context.filesDir
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdirs()
|
||||||
|
}
|
||||||
|
return File(dir, "${System.currentTimeMillis()}.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
fun getVersionName(): String {
|
fun getVersionName(): String {
|
||||||
try {
|
try {
|
||||||
val packageManager = appContext.packageManager
|
val packageManager = appContext.packageManager
|
||||||
|
|||||||
+3
-3
@@ -26,7 +26,7 @@ object JTPrinterUSB : UsbDeviceConnector(), PrinterInterface {
|
|||||||
val listUsbPort = AutoReplyPrint.CP_Port_EnumUsb_Helper.EnumUsb()
|
val listUsbPort = AutoReplyPrint.CP_Port_EnumUsb_Helper.EnumUsb()
|
||||||
if (listUsbPort != null) {
|
if (listUsbPort != null) {
|
||||||
for (usbPort in listUsbPort) {
|
for (usbPort in listUsbPort) {
|
||||||
if (usbPort.contains(vId.toString()) && usbPort.contains(pId.toString())) {
|
if (usbPort.contains(vId) && usbPort.contains(pId)) {
|
||||||
// 检测到巨天打印机,视为连接成功
|
// 检测到巨天打印机,视为连接成功
|
||||||
setVId(vId)
|
setVId(vId)
|
||||||
setPId(pId)
|
setPId(pId)
|
||||||
@@ -74,7 +74,7 @@ object JTPrinterUSB : UsbDeviceConnector(), PrinterInterface {
|
|||||||
if (listUsbPort != null) {
|
if (listUsbPort != null) {
|
||||||
for (usbPort in listUsbPort) {
|
for (usbPort in listUsbPort) {
|
||||||
// usbPort 格式为 "VID:0x4B43,PID:0x0FE6"
|
// usbPort 格式为 "VID:0x4B43,PID:0x0FE6"
|
||||||
if (usbPort.contains(getVId().toString()) && usbPort.contains(getPId().toString())) {
|
if (usbPort.contains(getVId()) && usbPort.contains(getPId())) {
|
||||||
h = AutoReplyPrint.INSTANCE.CP_Port_OpenUsb(usbPort, 1)
|
h = AutoReplyPrint.INSTANCE.CP_Port_OpenUsb(usbPort, 1)
|
||||||
AutoReplyPrint.INSTANCE.CP_Printer_AddOnPrinterStatusEvent({ handle: Pointer, printerErrorStatus: Long, printerInfoStatus: Long, privateData: Pointer ->
|
AutoReplyPrint.INSTANCE.CP_Printer_AddOnPrinterStatusEvent({ handle: Pointer, printerErrorStatus: Long, printerInfoStatus: Long, privateData: Pointer ->
|
||||||
if (CP_RTSTATUS_Helper.CP_RTSTATUS_NOPAPER(printerErrorStatus)) {
|
if (CP_RTSTATUS_Helper.CP_RTSTATUS_NOPAPER(printerErrorStatus)) {
|
||||||
@@ -237,4 +237,4 @@ object JTPrinterUSB : UsbDeviceConnector(), PrinterInterface {
|
|||||||
// usbManager.requestPermission(usbDevice, pendingIntent)
|
// usbManager.requestPermission(usbDevice, pendingIntent)
|
||||||
// return false
|
// return false
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|||||||
+3
-3
@@ -10,8 +10,8 @@ import com.bbitcn.f8.pad.utils.externalModules.devices.printer.JTPrinterUSB.resi
|
|||||||
import com.bbitcn.f8.pad.utils.externalModules.manager.bluetooth.MyBlueTooth
|
import com.bbitcn.f8.pad.utils.externalModules.manager.bluetooth.MyBlueTooth
|
||||||
import com.blankj.utilcode.util.TimeUtils
|
import com.blankj.utilcode.util.TimeUtils
|
||||||
import cpcl.PrinterHelper
|
import cpcl.PrinterHelper
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@@ -344,7 +344,7 @@ object PrinterBT : MyBlueTooth(), PrinterInterface {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
setState(0)
|
setState(0)
|
||||||
GlobalScope.launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
setState(withContext(Dispatchers.IO) {
|
setState(withContext(Dispatchers.IO) {
|
||||||
val result =
|
val result =
|
||||||
if (PrinterHelper.portOpenBT(MyApp.appContext, mac) == 0) 1 else -1
|
if (PrinterHelper.portOpenBT(MyApp.appContext, mac) == 0) 1 else -1
|
||||||
@@ -437,4 +437,4 @@ object PrinterBT : MyBlueTooth(), PrinterInterface {
|
|||||||
return Base64.encodeToString(byteArray, Base64.DEFAULT)
|
return Base64.encodeToString(byteArray, Base64.DEFAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-3
@@ -70,7 +70,12 @@ object FaceRecognize {
|
|||||||
image = base64,
|
image = base64,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val userList = result.result.userList
|
if (result.errorCode != 0) {
|
||||||
|
return "false" to result.errorMsg.ifBlank { "人脸识别失败" }
|
||||||
|
}
|
||||||
|
val faceResult = result.result
|
||||||
|
?: return "false" to result.errorMsg.ifBlank { "未识别到人脸" }
|
||||||
|
val userList = faceResult.userList
|
||||||
if (userList.size > 1) {
|
if (userList.size > 1) {
|
||||||
return "false" to "识别到多个人,请重新识别"
|
return "false" to "识别到多个人,请重新识别"
|
||||||
} else if (userList.isEmpty()) {
|
} else if (userList.isEmpty()) {
|
||||||
@@ -80,7 +85,7 @@ object FaceRecognize {
|
|||||||
} else {
|
} else {
|
||||||
val user = userList[0]
|
val user = userList[0]
|
||||||
MyLog.network("faceRecognize result: ${user.userId}")
|
MyLog.network("faceRecognize result: ${user.userId}")
|
||||||
return user.userId.replace("_", "-") to result.result.faceToken
|
return user.userId.replace("_", "-") to faceResult.faceToken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "false" to "图片有误"
|
return "false" to "图片有误"
|
||||||
@@ -116,4 +121,4 @@ object FaceRecognize {
|
|||||||
inputStream?.close()
|
inputStream?.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -3,7 +3,6 @@ package com.bbitcn.f8.pad.utils.externalModules.devices.reader.face
|
|||||||
import com.alibaba.sdk.android.oss.OSS
|
import com.alibaba.sdk.android.oss.OSS
|
||||||
import com.alibaba.sdk.android.oss.OSSClient
|
import com.alibaba.sdk.android.oss.OSSClient
|
||||||
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider
|
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider
|
||||||
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider
|
|
||||||
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
|
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
|
||||||
import com.bbitcn.f8.pad.MyApp
|
import com.bbitcn.f8.pad.MyApp
|
||||||
import com.bbitcn.f8.pad.ui.screen.view.Toasty.showTipsDialog
|
import com.bbitcn.f8.pad.ui.screen.view.Toasty.showTipsDialog
|
||||||
@@ -28,4 +27,4 @@ object OssUtils {
|
|||||||
// 创建OSSClient实例
|
// 创建OSSClient实例
|
||||||
return OSSClient(MyApp.appContext, config.endPoint, credentialProvider)
|
return OSSClient(MyApp.appContext, config.endPoint, credentialProvider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -7,7 +7,6 @@ import com.bbitcn.f8.pad.utils.MMKVUtil
|
|||||||
import com.bbitcn.f8.pad.utils.log.MyLog
|
import com.bbitcn.f8.pad.utils.log.MyLog
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -111,7 +110,7 @@ abstract class DeviceController {
|
|||||||
onIO: suspend () -> T,
|
onIO: suspend () -> T,
|
||||||
onUI: (T) -> Unit,
|
onUI: (T) -> Unit,
|
||||||
) {
|
) {
|
||||||
GlobalScope.launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
val result = runCatching {
|
val result = runCatching {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
@@ -151,4 +150,4 @@ abstract class DeviceController {
|
|||||||
|
|
||||||
abstract fun getDeviceName(): String
|
abstract fun getDeviceName(): String
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ abstract class MyBlueTooth : BluetoothDeviceConnector() {
|
|||||||
|
|
||||||
var devicesFound: MutableList<BluetoothDevice> = mutableStateListOf()
|
var devicesFound: MutableList<BluetoothDevice> = mutableStateListOf()
|
||||||
val mClient: BluetoothClient? by lazy {
|
val mClient: BluetoothClient? by lazy {
|
||||||
MyApp.appContext?.let { BluetoothClient(MyApp.appContext) }
|
BluetoothClient(MyApp.appContext)
|
||||||
}
|
}
|
||||||
val mBleConnectStatusListener: BleConnectStatusListener = object : BleConnectStatusListener() {
|
val mBleConnectStatusListener: BleConnectStatusListener = object : BleConnectStatusListener() {
|
||||||
override fun onConnectStatusChanged(mac: String, status: Int) {
|
override fun onConnectStatusChanged(mac: String, status: Int) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ object CrashHandlerUtil : Thread.UncaughtExceptionHandler {
|
|||||||
Thread.setDefaultUncaughtExceptionHandler(this)
|
Thread.setDefaultUncaughtExceptionHandler(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun uncaughtException(thread: Thread?, ex: Throwable) {
|
override fun uncaughtException(thread: Thread, ex: Throwable) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
MyLog.appError("软件已崩溃:" + getFormattedException(ex))
|
MyLog.appError("软件已崩溃:" + getFormattedException(ex))
|
||||||
Toasty.showConfirmDialog("软件已崩溃,请重启\n" + getFormattedException(ex)) {
|
Toasty.showConfirmDialog("软件已崩溃,请重启\n" + getFormattedException(ex)) {
|
||||||
@@ -44,4 +44,4 @@ object CrashHandlerUtil : Thread.UncaughtExceptionHandler {
|
|||||||
return stringBuilder.toString()
|
return stringBuilder.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Protocol
|
import okhttp3.Protocol
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
@@ -70,8 +70,7 @@ object RetrofitClient {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
MyLog.networkError("请求网络时发生异常:${e.message}")
|
MyLog.networkError("请求网络时发生异常:${e.message}")
|
||||||
MyLog.networkError("错误类型:${e.javaClass.simpleName},错误信息:${e.message}")
|
MyLog.networkError("错误类型:${e.javaClass.simpleName},错误信息:${e.message}")
|
||||||
val responseBody =
|
val responseBody = "{}".toResponseBody("application/json".toMediaTypeOrNull())
|
||||||
ResponseBody.create("application/json".toMediaTypeOrNull(), "{}")
|
|
||||||
val fakeResponse: Response =
|
val fakeResponse: Response =
|
||||||
if (e is UnknownHostException || e is SocketTimeoutException || e is ConnectException) {
|
if (e is UnknownHostException || e is SocketTimeoutException || e is ConnectException) {
|
||||||
Response.Builder()
|
Response.Builder()
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ class DryCocoonAirDetailPagingSource(tlsysid: String) :
|
|||||||
|
|
||||||
override suspend fun fetchData(
|
override suspend fun fetchData(
|
||||||
pageInfoJsonStr: String,
|
pageInfoJsonStr: String,
|
||||||
tlsysid: String
|
requestData: String
|
||||||
): List<DryCocoonAirDetailListResponse.Data> {
|
): List<DryCocoonAirDetailListResponse.Data> {
|
||||||
return apiService.getDryCocoonAirDetailList(pageInfoJsonStr, DryCocoonAirDetailListRequest(tlsysid)).data // 返回数据列表
|
return apiService.getDryCocoonAirDetailList(pageInfoJsonStr, DryCocoonAirDetailListRequest(requestData)).data // 返回数据列表
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ class DryCocoonAirPagingSource(request: DryCocoonAirListRequest) :
|
|||||||
|
|
||||||
override suspend fun fetchData(
|
override suspend fun fetchData(
|
||||||
pageInfoJsonStr: String,
|
pageInfoJsonStr: String,
|
||||||
request: DryCocoonAirListRequest
|
requestData: DryCocoonAirListRequest
|
||||||
): List<DryCocoonAirListResponse.Data> {
|
): List<DryCocoonAirListResponse.Data> {
|
||||||
return apiService.getDryCocoonAirList(pageInfoJsonStr, request).data
|
return apiService.getDryCocoonAirList(pageInfoJsonStr, requestData).data
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ class DryCocoonInDetailPagingSource(rksysid: String) :
|
|||||||
|
|
||||||
override suspend fun fetchData(
|
override suspend fun fetchData(
|
||||||
pageInfoJsonStr: String,
|
pageInfoJsonStr: String,
|
||||||
rksysid: String
|
requestData: String
|
||||||
): List<DryCocoonInDetailResponse.Data> {
|
): List<DryCocoonInDetailResponse.Data> {
|
||||||
return apiService.getDryCocoonInDetailList(pageInfoJsonStr, rksysid).data // 返回数据列表
|
return apiService.getDryCocoonInDetailList(pageInfoJsonStr, requestData).data // 返回数据列表
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ class DryCocoonOutDetailPagingSource(rksysid: String) :
|
|||||||
|
|
||||||
override suspend fun fetchData(
|
override suspend fun fetchData(
|
||||||
pageInfoJsonStr: String,
|
pageInfoJsonStr: String,
|
||||||
rksysid: String
|
requestData: String
|
||||||
): List<DryCocoonOutDetailResponse.Data> {
|
): List<DryCocoonOutDetailResponse.Data> {
|
||||||
return apiService.getDryCocoonOutDetailList(pageInfoJsonStr, rksysid).data // 返回数据列表
|
return apiService.getDryCocoonOutDetailList(pageInfoJsonStr, requestData).data // 返回数据列表
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ class DryCocoonStoreDetailPagingSource(data: DryCocoonStoreDetailListRequest) :
|
|||||||
|
|
||||||
override suspend fun fetchData(
|
override suspend fun fetchData(
|
||||||
pageInfoJsonStr: String,
|
pageInfoJsonStr: String,
|
||||||
data: DryCocoonStoreDetailListRequest,
|
requestData: DryCocoonStoreDetailListRequest,
|
||||||
): List<DryCocoonStoreDetailListResponse.Data> {
|
): List<DryCocoonStoreDetailListResponse.Data> {
|
||||||
return apiService.getDryCocoonStoreDetailList(pageInfoJsonStr, data.tlsysid,data.like).data // 返回数据列表
|
return apiService.getDryCocoonStoreDetailList(pageInfoJsonStr, requestData.tlsysid,requestData.like).data // 返回数据列表
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user