2 Commits
18 changed files with 514 additions and 71 deletions
+5
View File
@@ -1,3 +1,5 @@
import org.gradle.kotlin.dsl.implementation
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
@@ -104,4 +106,7 @@ dependencies {
implementation(libs.androidx.fragment.ktx)
// 图片加载
implementation(libs.glide)
implementation(libs.core)
implementation(libs.android.core)
}
+2 -1
View File
@@ -12,8 +12,9 @@ class MyApp : App() {
override fun onCreate() {
super.onCreate()
Timber.plant(Timber.DebugTree())
val deviceId = AppUtil.getUDID(this)
var deviceId = AppUtil.getUDID(this)
Timber.d("UDID = ${AppUtil.getUDID(this)}")
deviceId = "3ea47dc0-3cf0-3c2f-909c-265a9a65572e"
GlobalData.deviceId = deviceId
}
}
@@ -0,0 +1,84 @@
package com.sw.dualscreen.activity
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.view.WindowManager
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.sw.dualscreen.R
import com.sw.dualscreen.view.CustomDialog
import com.sw.dualscreen.viewmodel.BaseViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import timber.log.Timber
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
protected lateinit var binding: VB
protected lateinit var context: Context
private var mDialogWaiting: CustomDialog? = null
private lateinit var viewModel: BaseViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
context = this
//保持亮屏
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
binding = inflateViewBinding()
setContentView(binding.root)
viewModel = getViewModel()
initialize()
registerDataChange()
}
abstract fun getViewModel(): BaseViewModel
protected abstract fun inflateViewBinding(): VB
open fun initialize() {
}
open fun registerDataChange() {
lifecycleScope.launch {
viewModel.showLoading.collect {
Timber.d("registerDataChange 用户 showLoading = $it")
if (it) {
showWaitingDialog("")
} else {
hideWaitingDialog()
}
}
}
}
/**
* 显示等待提示框
*/
fun showWaitingDialog(tip: String?): Dialog? {
hideWaitingDialog()
val view = View.inflate(this, R.layout.dialog_waiting, null)
if (!TextUtils.isEmpty(tip)) (view.findViewById<View?>(R.id.tvTip) as TextView).text = tip
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show()
mDialogWaiting!!.setCancelable(true)
return mDialogWaiting
}
/**
* 隐藏等待提示框
*/
fun hideWaitingDialog() {
mDialogWaiting?.dismiss()
mDialogWaiting = null
}
}
@@ -5,35 +5,48 @@ import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat.startActivity
import androidx.lifecycle.lifecycleScope
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.databinding.ActivityInitBinding
import com.sw.dualscreen.utils.QRCodeUtil
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.DeviceViewModel
import com.sw.plate.utils.AppUtil
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
class InitActivity : AppCompatActivity() {
private lateinit var binding: ActivityInitBinding
class InitActivity : BaseActivity<ActivityInitBinding>() {
private val viewModel by viewModels<DeviceViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityInitBinding.inflate(layoutInflater)
setContentView(binding.root)
val deviceId = AppUtil.getUDID(this)
override fun getViewModel(): BaseViewModel {
return viewModel
}
override fun inflateViewBinding(): ActivityInitBinding {
return ActivityInitBinding.inflate(layoutInflater)
}
override fun initialize() {
super.initialize()
val isSuccess = viewModel.checkEquipmentInfo()
if (isSuccess) {
goMainActivity()
return
}
binding.tvDeviceId.text = deviceId
binding.btConfirm.setOnClickListener {
binding.imgQr.setImageBitmap(
QRCodeUtil.generateQRCode(
content = GlobalData.deviceId,
size = 200
)
)
binding.initButton.setOnClickListener {
viewModel.getDeviceToken()
}
registerDataChange()
}
private fun registerDataChange() {
override fun registerDataChange() {
super.registerDataChange()
lifecycleScope.launch {
viewModel.deviceInfoResult.drop(1).collect {
if (it != true) return@collect
@@ -36,6 +36,8 @@ import com.sw.dualscreen.presentation.SecondaryScreenPresentation
import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.utils.GlideUtils
import com.sw.dualscreen.view.CustomBottomSheetDialog
import com.sw.dualscreen.view.CustomDialog
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
@@ -44,8 +46,7 @@ import timber.log.Timber
import java.io.File
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
class MainActivity : BaseActivity<ActivityMainBinding>() {
private val viewModel by viewModels<UserViewModel>()
private var imageCapture: ImageCapture? = null
private var isAnalyzing = true // 控制是否进行图像分析
@@ -59,12 +60,16 @@ class MainActivity : AppCompatActivity() {
private var bottomSheetDialog: CustomBottomSheetDialog? = null
private var lastWeight: Double = 0.0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.main)
override fun getViewModel(): BaseViewModel {
return viewModel
}
override fun inflateViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
}
override fun initialize() {
super.initialize()
initView()
setupSecondaryDisplay()
setupCamera()
@@ -94,7 +99,7 @@ class MainActivity : AppCompatActivity() {
val spinnerAdapter = ArrayAdapter<String>(
this,
R.layout.item_for_custom_spinner,
arrayOf("即放即取", "持续取餐")
arrayOf("即放即取", "余量取餐")
)
binding.spinner.adapter = spinnerAdapter
binding.spinner.setSelection(0)
@@ -105,12 +110,10 @@ class MainActivity : AppCompatActivity() {
position: Int,
id: Long
) {
presentation.updateMealPickupMode(position)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
adapter = createAdapter()
binding.recyclerview.layoutManager = GridLayoutManager(this, 2)
@@ -126,7 +129,6 @@ class MainActivity : AppCompatActivity() {
binding.tvFoodName.setOnClickListener {
SensorScaleUtils.zero()
}
registerDataChange()
}
fun updateCurrentFood(foodInfo: FoodInfo?) {
@@ -154,7 +156,8 @@ class MainActivity : AppCompatActivity() {
}
}
private fun registerDataChange() {
override fun registerDataChange() {
super.registerDataChange()
lifecycleScope.launch {
viewModel.identifiedFoodInfoList.collect { list ->
binding.recyclerview
@@ -1,6 +1,7 @@
package com.sw.dualscreen.presentation
import android.Manifest
import android.R.attr.visibility
import android.app.Presentation
import android.content.Context
import android.content.pm.PackageManager
@@ -11,7 +12,6 @@ import android.hardware.Camera
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import android.view.Display
import android.view.View
import android.view.ViewGroup
@@ -69,19 +69,18 @@ class SecondaryScreenPresentation(
// 当前食物信息
private var currentFood: FoodInfo? = null
private var lastFood: FoodInfo? = null
private var userNutritionData: UserNutritionData? = null
private var dinnerTypeInfo: DinnerTypeInfo? = null
private lateinit var itemUserNutritionBinding: ItemUserNutritionBinding
private lateinit var stepChangeCallback: (Int) -> Unit
// 上一次的计算热量结果
private var lastCalcResultInfo: UserNutritionUtils.CalcResultInfo? = null
private var lastWeight = 0.0
private val debouncer = Debouncer(500)
private var faceTime: Long = 0L // 人脸识别时的时间
private var recognitionTime: Long = 0L // 人脸识别时的时间
private var recognitionWeight: Double = 0.0 // 人脸识别时的重量
private var lastFaceTrackId: Int = 0 // 上一次的人脸信息
private var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐
// 当前步骤
var currentStep: Int = 0
@@ -99,6 +98,13 @@ class SecondaryScreenPresentation(
}
private fun registerDataChange() {
activity.lifecycleScope.launch {
viewModel.loadFaceResult.collect { needUpdate ->
if (needUpdate){
recognizeViewModel.refreshFaceList()
}
}
}
activity.lifecycleScope.launch {
viewModel.nutritionData.collect {
Timber.d("registerDataChange nutritionData = $it")
@@ -161,8 +167,6 @@ class SecondaryScreenPresentation(
dinnerTypeInfo = null
currentFood = null
userNutritionData = null
lastFood = null
lastCalcResultInfo = null
recognitionWeight = 0.0
stepChangeCallback(currentStep)
@@ -182,6 +186,11 @@ class SecondaryScreenPresentation(
fun step2(foodInfo: FoodInfo) {
Timber.d("step2")
currentStep = 2
dinnerTypeInfo = null
userNutritionData = null
recognitionWeight = 0.0
stepChangeCallback(currentStep)
currentFood = foodInfo
viewModel.getDinnerType()
@@ -191,7 +200,10 @@ class SecondaryScreenPresentation(
binding.flPreview.visibility = View.GONE
// binding.flFace.visibility = View.VISIBLE
binding.flFace.post {
binding.flFace.visibility = View.VISIBLE
}
binding.ivFaceBg.visibility = View.VISIBLE
binding.tvFaceTip.visibility = View.VISIBLE
binding.tvBottomTip.visibility = View.VISIBLE
@@ -262,6 +274,14 @@ class SecondaryScreenPresentation(
calculateNutrition(recognitionWeight - lastWeight)
}
/**
* 余量取餐
*/
fun updateMealPickupMode(mode: Int) {
Timber.d("updateMealPickupMode mode = $mode")
mealPickupMode = mode
}
private fun calculateNutrition(weight: Double) {
debouncer.debounce {
Timber.d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight")
@@ -274,11 +294,6 @@ class SecondaryScreenPresentation(
dinnerType = dinnerType
)
Timber.d("calculateNutrition calcResultInfo = $calcResultInfo")
if (lastCalcResultInfo == calcResultInfo) {
Timber.d("calculateNutrition 与上次计算结果无变化")
return@debounce
}
lastCalcResultInfo = calcResultInfo
val columnMax = UserNutritionUtils.getMaxInt(calcResultInfo)
activity.runOnUiThread {
@@ -346,7 +361,7 @@ class SecondaryScreenPresentation(
}
try {
val cameraCount = Camera.getNumberOfCameras()
if (cameraCount < 3){
if (cameraCount < 3) {
ToastUtils.showToast("摄像头数量异常")
return
}
@@ -418,14 +433,14 @@ class SecondaryScreenPresentation(
Timber.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
})
recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? ->
// Timber.i("recognizeNotice observe notice = $notice")
Timber.i("recognizeNotice observe notice = $notice")
})
recognizeViewModel.recognizeUserId.observe(
activity,
Observer { compareResult: CompareResult ->
Timber.i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}")
faceTime = System.currentTimeMillis()
recognitionTime = System.currentTimeMillis()
recognitionWeight = lastWeight
lastFaceTrackId = compareResult.trackId
val faceEntity = compareResult.faceEntity
@@ -701,7 +716,11 @@ class SecondaryScreenPresentation(
Timber.i("$lastFaceTrackId 用户离开")
lastFaceTrackId = 0
postUserData()
if (mealPickupMode == 0) {
step1()
}else{
step2(currentFood!!)
}
}
}
}
@@ -715,7 +734,7 @@ class SecondaryScreenPresentation(
val userNutritionParam = UserNutritionParam(
userId = userNutritionData?.userId!!,
foodId = currentFood?.id!!,
faceTime = faceTime,
faceTime = recognitionTime,
faceEndTime = System.currentTimeMillis(),
eatWeight = recognitionWeight - lastWeight,
foodWeight = lastWeight
@@ -0,0 +1,99 @@
package com.sw.dualscreen.utils
import android.graphics.Bitmap
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
/**
* 二维码生成工具类
*/
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 = android.graphics.Canvas(this)
canvas.drawBitmap(qrCode, 0f, 0f, null)
canvas.drawBitmap(scaledLogo, offset.toFloat(), offset.toFloat(), null)
}
}
}
@@ -0,0 +1,88 @@
package com.sw.dualscreen.view;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class CustomDialog extends Dialog {
/**
* 宽高由布局文件中指定(但是最底层的宽度无效,可以多嵌套一层解决)
*/
public CustomDialog(Context context, View layout, int style) {
super(context, style);
setContentView(layout);
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
/**
* 宽高由该方法的参数设置
*/
public CustomDialog(Context context, int width, int height, View layout,
int style) {
super(context, style);
// 设置内容
setContentView(layout);
// 设置窗口属性
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
// 设置宽度、高度、密度、对齐方式
float density = getDensity(context);
params.width = (int) (width * density);
params.height = (int) (height * density);
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
/**
* 获取显示密度
*
* @param context
* @return
*/
public float getDensity(Context context) {
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
return dm.density;
}
private void fullScreenImmersive(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_FULLSCREEN;
view.setSystemUiVisibility(uiOptions);
}
}
@Override
public void show() {
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
super.show();
// fullScreenImmersive(getWindow().getDecorView());
// this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}
}
@@ -1,5 +1,6 @@
package com.sw.dualscreen.viewmodel
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.model.response.EquipmentInfo
import com.sw.dualscreen.utils.GsonUtils
@@ -18,7 +19,7 @@ class DeviceViewModel : BaseViewModel() {
/**
* 获取token
*/
fun getDeviceToken(deviceId: String = "3ea47dc0-3cf0-3c2f-909c-265a9a65572e") {
fun getDeviceToken(deviceId: String = GlobalData.deviceId) {
launchWithLoading {
val response = repository.getDeviceToken(deviceId)
if (parseResponse(response)) {
@@ -45,11 +45,17 @@ class UserViewModel : BaseViewModel() {
private val _dinnerTypeInfo = MutableStateFlow<DinnerTypeInfo?>(null)
val dinnerTypeInfo: StateFlow<DinnerTypeInfo?> = _dinnerTypeInfo
/**
* 人脸加载完成
*/
private val _loadFaceResult = MutableStateFlow<Boolean>(false)
val loadFaceResult : StateFlow<Boolean> = _loadFaceResult
/**
* 获取token
*/
fun getEquipmentToken(qrcodeId: String = "3ea47dc0-3cf0-3c2f-909c-265a9a65572e") {
fun getEquipmentToken(qrcodeId: String = GlobalData.deviceId) {
Timber.d("getEquipmentToken")
launchWithLoading {
val response = repository.getEquipmentToken(qrcodeId)
@@ -70,6 +76,7 @@ class UserViewModel : BaseViewModel() {
fun getUserFaceCache(index: Int = 0) {
Timber.d("getUserFaceCache index = $index")
launch {
_loadFaceResult.value = false
val response = repository.getUserFaceCache(index)
if (parseResponse(response)) {
// 获取成功一次后缓存状态
@@ -80,11 +87,12 @@ class UserViewModel : BaseViewModel() {
FaceEntity(it.userId, null, Base64.decode(it.faceFeatureString))
}
faceApi.updateFaceData(index, faceEntity)
activeEngine()
}
val nextPageIndex = response.result?.nextPageIndex ?: -1
if (nextPageIndex > 0) {
getUserFaceCache(nextPageIndex)
} else{
_loadFaceResult.value = true
}
}
}
@@ -129,13 +137,6 @@ class UserViewModel : BaseViewModel() {
})
}
/**
* 重置用户信息
*/
fun resetUserInfo() {
Timber.d("resetUserInfo")
}
fun getIdentifiedFoodList() {
Timber.d("identifiedFoodList")
launchWithLoading {
@@ -180,7 +181,7 @@ class UserViewModel : BaseViewModel() {
fun getUserNutritionData(userId: String, foodId: String) {
Timber.d("getUserNutritionData userId = ${userId}, foodId = $foodId")
_nutritionData.value = null
launchWithLoading {
launch {
val response = repository.getUserNutritionData(userId = userId, foodId = foodId)
if (parseResponse(response)) {
_nutritionData.value = response.result
@@ -191,7 +192,7 @@ class UserViewModel : BaseViewModel() {
fun getDinnerType() {
Timber.d("getDinnerType")
_dinnerTypeInfo.value = null
launchWithLoading {
launch {
val response = repository.getDinnerType()
if (parseResponse(response)) {
_dinnerTypeInfo.value = response.result
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#ff08C6DC" />
<corners android:radius="8dp" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<solid android:color="@color/black" />
</shape>
+78 -11
View File
@@ -1,23 +1,90 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".activity.InitActivity">
android:orientation="vertical">
<LinearLayout
android:id="@+id/welcomeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:gravity="center"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />
</LinearLayout>
<RelativeLayout
android:id="@+id/initRelLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:padding="48dp">
<ImageView
android:id="@+id/mainImgView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="200dp"
android:src="@mipmap/img_init" />
<TextView
android:id="@+id/tv_deviceId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="1111" />
android:id="@+id/okButton"
android:layout_width="200dp"
android:layout_height="52dp"
android:layout_below="@+id/mainImgView"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:background="@drawable/bg_init_button"
android:gravity="center"
android:text="连接服务器"
android:textColor="@color/white"
android:textSize="22sp"
android:visibility="gone"
android:textStyle="bold" />
<Button
android:id="@+id/bt_confirm"
<TextView
android:id="@+id/initButton"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_below="@+id/mainImgView"
android:layout_centerHorizontal="true"
android:layout_marginTop="160dp"
android:padding="10dp"
android:background="@drawable/bg_init_button"
android:gravity="center"
android:text="设备初始化"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="@+id/activeArcsoft"
android:layout_width="300dp"
android:layout_height="68dp"
android:layout_below="@+id/okButton"
android:layout_centerHorizontal="true"
android:layout_marginTop="40dp"
android:background="@drawable/bg_init_button"
android:gravity="center"
android:text="虹软激活"
android:textColor="@color/white"
android:textSize="32sp"
android:textStyle="bold"
android:visibility="gone" />
<ImageView
android:id="@+id/imgQr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="获取" />
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true" />
</RelativeLayout>
</LinearLayout>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="240dp"
android:layout_height="80dp"
android:background="@drawable/dialog_waiting">
<TextView
android:id="@+id/tvTip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@color/white"
android:text="请稍等"
android:textSize="22sp" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="30dp"
android:layout_toLeftOf="@id/tvTip"
android:indeterminateTint="@color/teal_200"
android:indeterminateTintMode="src_atop" />
</RelativeLayout>
</FrameLayout>
Binary file not shown.

After

Width:  |  Height:  |  Size: 999 KiB

+1 -1
View File
@@ -7,7 +7,7 @@
<color name="beige_ECE7D0">#ECE7D0</color>
<color name="blue_6498DD">#6498DD</color>
<color name="black_031127">#031127</color>
<color name="teal_200">#FF03DAC5</color>
<color name="identify_checked">#031127</color>
<color name="identify_normal">#6498DD</color>
<color name="search_checked">#FF9900</color>
+14
View File
@@ -116,4 +116,18 @@
<item name="android:textStyle">bold</item>
<item name="android:layout_centerHorizontal">true</item>
</style>
<!--圆角Dialog-->
<style name="MyDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.6</item>
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
</style>
</resources>
+4
View File
@@ -1,5 +1,7 @@
[versions]
agp = "8.10.1"
core = "3.4.1"
androidCore = "3.3.0"
glide = "4.16.0"
kotlin = "2.0.21"
coreKtx = "1.10.1"
@@ -25,6 +27,8 @@ lifecycleViewmodelKtx = "2.8.3"
lifecycleRuntimeKtx = "2.8.3"
[libraries]
android-core = { module = "com.google.zxing:android-core", version.ref = "androidCore" }
core = { module = "com.google.zxing:core", version.ref = "core" }
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }