增加初始化页面

This commit is contained in:
2025-09-17 17:42:38 +08:00
parent 7f56d4d1a1
commit 73456046c5
24 changed files with 549 additions and 35 deletions
+8
View File
@@ -4,6 +4,14 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-09-17T07:41:36.397341700Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="Default" identifier="serial=192.168.1.80:5555;connection=28be19dc" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
-1
View File
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="zulu-17" project-jdk-type="JavaSDK">
+3
View File
@@ -95,4 +95,7 @@ dependencies {
// implementation(libs.adapter.coroutines)
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation(libs.core)
implementation(libs.android.core)
}
+9 -3
View File
@@ -21,11 +21,13 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher512"
android:icon="@mipmap/ic_logo512"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher512"
android:roundIcon="@mipmap/ic_logo512"
android:supportsRtl="true"
android:theme="@style/Theme.SmartPlateCabinet"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<!-- 注册BootReceiver,监听开机完成广播 -->
<receiver
@@ -48,10 +50,14 @@
<activity
android:name=".activity.LoginByPwdActivity"
android:exported="false"
android:launchMode="singleTask"></activity>
android:launchMode="singleTask"/>
<activity
android:name=".activity.LoginByFaceActivity"
android:exported="true"
android:launchMode="singleTask"/>
<activity
android:name=".activity.DeviceInitActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -29,6 +29,17 @@ object GlobalData {
var appId = "Hkz1rBk6PZXbS8KwKr67K2eZtsz8bRoMHLg64bUdgCZj"
var sdkKey = "AabXs3sHM8UhhE7oCGf4LVMLrdkGb1nJNksbjjTdVt7k"
var activeKey = "085F-118G-Q391-53YL"
/**
* 具体业务baseurl
*/
var appBaseUrl: String = ""
/**
* 设备id
*/
var deviceId: String = ""
var restId: String = ""
}
/**
@@ -45,6 +56,7 @@ object Constants {
* key
*/
object GlobalKey {
const val KEY_EQUIPMENT_INFO = "equipmentInfo"
const val KEY_TOKEN = "tokenKey"
const val KEY_FIRST_RUN = "firstRun"
const val KEY_USER_INFO = "userInfoKey"
@@ -0,0 +1,72 @@
package com.sw.platecabinet.activity
import android.content.Intent
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import com.sw.plate.utils.AppUtil
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.databinding.ActivityDeviceInitBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.utils.QRCodeUtil
import com.sw.platecabinet.viewmodel.DeviceViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.getValue
/**
* 设备初始化界面
*/
class DeviceInitActivity : BaseActivity<ActivityDeviceInitBinding>() {
private val deviceViewModel by viewModels<DeviceViewModel>()
override fun inflateViewBinding(): ActivityDeviceInitBinding {
return ActivityDeviceInitBinding.inflate(layoutInflater)
}
override fun inflateTitleBinding(): ItemTitleTimeBinding? {
return null
}
override fun initialize() {
var deviceId = AppUtil.getUDID(this)
deviceId = "6ce7cd59-b875-38b2-b73d-88a570be3212"
GlobalData.deviceId = deviceId
val isSuccess = deviceViewModel.checkEquipmentInfo()
if (isSuccess) {
goLoginActivity()
return
}
binding.ivQrCode.setImageBitmap(
QRCodeUtil.generateQRCode(
content = GlobalData.deviceId,
size = 200
)
)
binding.btnInit.setOnClickListener {
deviceViewModel.getDeviceToken()
}
}
override fun registerDataChange() {
super.registerDataChange()
lifecycleScope.launch {
deviceViewModel.deviceInfoResult.collect { it ->
if (it == true) {
goLoginActivity()
}
}
}
}
private fun goLoginActivity() {
val intent = Intent(this, LoginByFaceActivity::class.java)
startActivity(intent)
finish()
}
override fun onLeftDoubleClick() {
}
}
@@ -4,7 +4,8 @@ data class ApiResponse<T>(
val code: Int,
val success: Boolean? = false,
val msg: String? = "",
val data: T? = null
val data: T? = null,
val result: T? = null,
) {
fun isSuccess(): Boolean = code == 200
}
@@ -0,0 +1,72 @@
package com.sw.platecabinet.model.response
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class EquipmentInfo(
@SerializedName("appPackageLocalUrl")
val appPackageLocalUrl: String? = "",
@SerializedName("appPackageUrl")
val appPackageUrl: String? = "",
@SerializedName("arcsoftActiveKey")
val arcsoftActiveKey: String? = "",
@SerializedName("arcsoftAppId")
val arcsoftAppId: String? = "",
@SerializedName("arcsoftSdkKey")
val arcsoftSdkKey: String? = "",
@SerializedName("arrayCross")
val arrayCross: Int? = 0,
@SerializedName("arrayMode")
val arrayMode: String? = "",
@SerializedName("arrayVertical")
val arrayVertical: Int? = 0,
@SerializedName("canteenId")
val canteenId: String? = "",
@SerializedName("canteenName")
val canteenName: String? = "",
@SerializedName("clientServerIp")
val clientServerIp: String? = "",
@SerializedName("createBy")
val createBy: String? = "",
@SerializedName("createTime")
val createTime: String? = "",
@SerializedName("customerName")
val customerName: String? = "",
@SerializedName("equipmentCode")
val equipmentCode: String? = "",
@SerializedName("equipmentName")
val equipmentName: String? = "",
@SerializedName("equipmentName_dictText")
val equipmentNameDictText: String? = "",
@SerializedName("id")
val id: String? = "",
@SerializedName("isSync")
val isSync: Int? = 0,
@SerializedName("mqName")
val mqName: String? = "",
@SerializedName("mqPassword")
val mqPassword: String? = "",
@SerializedName("orgCode")
val orgCode: String? = "",
@SerializedName("owningTrack")
val owningTrack: Int? = 0,
@SerializedName("owningTrackOrder")
val owningTrackOrder: Int? = 0,
@SerializedName("screenHtml")
val screenHtml: String? = "",
@SerializedName("serviceRequestAddress")
val serviceRequestAddress: String? = "",
@SerializedName("status")
val status: Int? = 0,
@SerializedName("sysOrgCode")
val sysOrgCode: String? = "",
@SerializedName("updateBy")
val updateBy: String? = "",
@SerializedName("updateTime")
val updateTime: String? = "",
@SerializedName("zhstServerIp")
val zhstServerIp: String? = ""
) : Parcelable
@@ -12,6 +12,7 @@ import java.util.concurrent.TimeUnit
object ApiClient {
private const val BASE_URL = "https://vip.shuziweidao.com"
private const val DEVICE_BASE_URL = "http://device.shuziweidao.com:8889/"
// private const val BASE_URL = "http://192.168.1.8:9092"
private const val TIME_OUT = 30L // 超时时间(秒)
@@ -33,7 +34,7 @@ object ApiClient {
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.baseUrl(DEVICE_BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
// .addCallAdapterFactory(CoroutineCallAdapterFactory()) // 协程适配器
@@ -1,25 +1,48 @@
package com.sw.platecabinet.network.api
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.model.request.BindParam
import com.sw.platecabinet.model.request.EquipmentParam
import com.sw.platecabinet.model.request.LoginParam
import com.sw.platecabinet.model.request.SearchParam
import com.sw.platecabinet.model.response.ApiResponse
import com.sw.platecabinet.model.response.EquipmentInfo
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.model.response.UserFaceModel
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.Query
import retrofit2.http.Url
interface ApiService {
/**
* device获取token
*/
@GET("sys/getEquipmentToken")
suspend fun getDeviceToken(
@Query("qrcodeId") qrcodeId: String,
@Query("appVersion") appVersion: String = GlobalData.appVersion
): ApiResponse<String>
/**
*获取配置信息
*/
@GET("equipment/stEquipment/queryByEquipmentCode")
suspend fun getDeviceInfo(
@Query("equipmentCode") equipmentCode: String,
@Query("appVersion") appVersion: String = GlobalData.appVersion,
@Header("X-Access-Token") token: String
): ApiResponse<EquipmentInfo>
/**
* 生成token
*/
@GET("/shuwei-zhct/scales/generateToken")
@GET//("/shuwei-zhct/scales/generateToken")
suspend fun generateToken(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/scales/generateToken",
@Query("deviceId") deviceId: String,
@Query("appVersion") appVersion: String,
@Query("equipmentCode") equipmentCode: String
@@ -28,8 +51,9 @@ interface ApiService {
/**
* 获取人脸数据
*/
@GET("/shuwei-zhct/scales/getUserFaceCache")
@GET//("/shuwei-zhct/scales/getUserFaceCache")
suspend fun getUserFaceCache(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/scales/getUserFaceCache",
@Query("appVersion") appVersion: String,
@Query("equipmentCode") equipmentCode: String
): ApiResponse<List<UserFaceModel>>
@@ -37,38 +61,56 @@ interface ApiService {
/**
* 餐盘用户信息获取
*/
@POST("/shuwei-zhct/swEquipmentRelUser/equipmentBoxLogin")
suspend fun equipmentBoxLogin(@Body param: LoginParam): ApiResponse<EquipmentUserInfo>
@POST//("/shuwei-zhct/swEquipmentRelUser/equipmentBoxLogin")
suspend fun equipmentBoxLogin(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/equipmentBoxLogin",
@Body param: LoginParam
): ApiResponse<EquipmentUserInfo>
/**
* 餐盘用户信息列表查询
*/
@POST("/shuwei-zhct/swEquipmentRelUser/list")
suspend fun getEquipmentList(@Body param: EquipmentParam): ApiResponse<List<EquipmentUserInfo>>
@POST//("/shuwei-zhct/swEquipmentRelUser/list")
suspend fun getEquipmentList(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/list",
@Body param: EquipmentParam
): ApiResponse<List<EquipmentUserInfo>>
/**
* 餐盘用户信息绑定解绑
*/
@POST("/shuwei-zhct/swEquipmentRelUser/addOrEdit")
suspend fun bindEquipment(@Body param: BindParam): ApiResponse<EquipmentUserInfo?>
@POST//("/shuwei-zhct/swEquipmentRelUser/addOrEdit")
suspend fun bindEquipment(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/addOrEdit",
@Body param: BindParam
): ApiResponse<EquipmentUserInfo?>
/**
* 用户信息模糊搜索
*/
@POST("/shuwei-user/swclientUserInfoShop/selectList")
suspend fun searchUser(@Body param: SearchParam): ApiResponse<SearchResult>
@POST//("/shuwei-user/swclientUserInfoShop/selectList")
suspend fun searchUser(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-user/swclientUserInfoShop/selectList",
@Body param: SearchParam
): ApiResponse<SearchResult>
/**
* 通过餐盘号获取信息
*/
@POST("/shuwei-zhct/swEquipmentRelUser/findByPlateNumber")
suspend fun findByPlateNumber(@Body param: BindParam): ApiResponse<EquipmentUserInfo>
@POST//("/shuwei-zhct/swEquipmentRelUser/findByPlateNumber")
suspend fun findByPlateNumber(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/swEquipmentRelUser/findByPlateNumber",
@Body param: BindParam
): ApiResponse<EquipmentUserInfo>
/**
* 获取人脸增量数据
*
* @param timeDate 时间戳(毫秒级)
*/
@GET("/shuwei-zhct/scales/getHeartbeatInterface")
suspend fun getHeartbeatInterface(@Query("timeDate") timeDate: Long): ApiResponse<List<UserFaceModel>>
@GET//("/shuwei-zhct/scales/getHeartbeatInterface")
suspend fun getHeartbeatInterface(
@Url url: String = "${GlobalData.appBaseUrl}/shuwei-zhct/scales/getHeartbeatInterface",
@Query("timeDate") timeDate: Long
): ApiResponse<List<UserFaceModel>>
}
@@ -6,6 +6,7 @@ import com.sw.platecabinet.model.request.EquipmentParam
import com.sw.platecabinet.model.request.LoginParam
import com.sw.platecabinet.model.request.SearchParam
import com.sw.platecabinet.model.response.ApiResponse
import com.sw.platecabinet.model.response.EquipmentInfo
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.model.response.UserFaceModel
@@ -17,15 +18,39 @@ import com.sw.platecabinet.network.api.ApiService
class RemoteRepository constructor(
private val apiService: ApiService
) : BaseRepository() {
/**
* 生成token
*/
suspend fun getDeviceToken(qrcodeId: String): ApiResponse<String> {
return safeApiCall {
apiService.getDeviceToken(
qrcodeId
)
}
}
/**
* 获取设备信息
*/
suspend fun getDeviceInfo(equipmentCode: String, token: String): ApiResponse<EquipmentInfo> {
return safeApiCall {
apiService.getDeviceInfo(
equipmentCode,
token = token
)
}
}
/**
* 生成token
*/
suspend fun generateToken(deviceId: String): ApiResponse<String> {
return safeApiCall {
apiService.generateToken(
deviceId,
GlobalData.appVersion,
GlobalData.globalEquipmentCode
deviceId = deviceId,
appVersion = GlobalData.appVersion,
equipmentCode = GlobalData.globalEquipmentCode
)
}
}
@@ -36,8 +61,8 @@ class RemoteRepository constructor(
suspend fun getUserFaceCache(): ApiResponse<List<UserFaceModel>> {
return safeApiCall {
apiService.getUserFaceCache(
GlobalData.appVersion,
GlobalData.globalEquipmentCode
appVersion = GlobalData.appVersion,
equipmentCode = GlobalData.globalEquipmentCode
)
}
}
@@ -46,35 +71,35 @@ class RemoteRepository constructor(
* 登录
*/
suspend fun equipmentBoxLogin(param: LoginParam): ApiResponse<EquipmentUserInfo> {
return safeApiCall { apiService.equipmentBoxLogin(param) }
return safeApiCall { apiService.equipmentBoxLogin(param = param) }
}
/**
* 获取设备绑定用户列表
*/
suspend fun getEquipmentList(param: EquipmentParam): ApiResponse<List<EquipmentUserInfo>> {
return safeApiCall { apiService.getEquipmentList(param) }
return safeApiCall { apiService.getEquipmentList(param = param) }
}
/**
* 餐盘用户信息绑定解绑
*/
suspend fun bindEquipment(param: BindParam): ApiResponse<EquipmentUserInfo?> {
return safeApiCall { apiService.bindEquipment(param) }
return safeApiCall { apiService.bindEquipment(param = param) }
}
/**
* 用户信息模糊搜索
*/
suspend fun searchUser(param: SearchParam): ApiResponse<SearchResult> {
return safeApiCall { apiService.searchUser(param) }
return safeApiCall { apiService.searchUser(param = param) }
}
/**
* 通过餐盘编号获取绑定信息
*/
suspend fun findByPlateNumber(param: BindParam): ApiResponse<EquipmentUserInfo> {
return safeApiCall { apiService.findByPlateNumber(param) }
return safeApiCall { apiService.findByPlateNumber(param = param) }
}
/**
@@ -83,6 +108,6 @@ class RemoteRepository constructor(
* @param timeDate 时间戳(毫秒级)
*/
suspend fun getHeartbeatInterface(timeDate: Long): ApiResponse<List<UserFaceModel>> {
return safeApiCall { apiService.getHeartbeatInterface(timeDate) }
return safeApiCall { apiService.getHeartbeatInterface(timeDate = timeDate) }
}
}
@@ -0,0 +1,103 @@
package com.sw.platecabinet.utils
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
import com.google.zxing.common.BitMatrix
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import kotlin.apply
import kotlin.ranges.until
import kotlin.text.isEmpty
/**
* 二维码生成工具类
*/
object QRCodeUtil {
/**
* 生成二维码(默认大小)
* @param content 二维码内容
* @return 生成的二维码Bitmap
*/
@JvmOverloads
fun generateQRCode(content: String, size: Int = 500): Bitmap? {
return generateQRCode(content, size, Color.BLACK, Color.WHITE)
}
/**
* 生成二维码(自定义颜色)
* @param content 二维码内容
* @param size 二维码边长(像素)
* @param colorCode 二维码颜色
* @param backgroundColor 背景颜色
* @return 生成的二维码Bitmap
*/
fun generateQRCode(
content: String,
size: Int,
colorCode: Int,
backgroundColor: Int
): Bitmap? {
if (content.isEmpty()) {
return null
}
return try {
val hints = mutableMapOf<EncodeHintType, Any>().apply {
put(EncodeHintType.CHARACTER_SET, "UTF-8")
put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H) // 纠错级别
put(EncodeHintType.MARGIN, 1) // 边距
}
val bitMatrix = QRCodeWriter().encode(
content,
BarcodeFormat.QR_CODE,
size,
size,
hints
)
val pixels = IntArray(size * size).apply {
for (y in 0 until size) {
for (x in 0 until size) {
this[y * size + x] = if (bitMatrix.get(x, y)) colorCode else backgroundColor
}
}
}
Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply {
setPixels(pixels, 0, size, 0, 0, size, size)
}
} catch (e: WriterException) {
e.printStackTrace()
null
}
}
/**
* 生成带Logo的二维码
* @param content 二维码内容
* @param size 二维码边长(像素)
* @param logo Logo Bitmap
* @return 带Logo的二维码Bitmap
*/
fun generateQRCodeWithLogo(content: String, size: Int, logo: Bitmap?): Bitmap? {
val qrCode = generateQRCode(content, size) ?: return null
logo ?: return qrCode
val logoSize = size / 5 // Logo大小约为二维码的1/5
val scaledLogo = Bitmap.createScaledBitmap(logo, logoSize, logoSize, false)
val offset = (size - logoSize) / 2
return Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply {
val canvas = Canvas(this)
canvas.drawBitmap(qrCode, 0f, 0f, null)
canvas.drawBitmap(scaledLogo, offset.toFloat(), offset.toFloat(), null)
}
}
}
@@ -3,7 +3,9 @@ package com.sw.platecabinet.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sw.plate.utils.ToastUtils
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.model.response.ApiResponse
import com.sw.platecabinet.model.response.EquipmentInfo
import com.sw.platecabinet.network.ApiClient
import com.sw.platecabinet.repository.RemoteRepository
import kotlinx.coroutines.flow.MutableStateFlow
@@ -62,4 +64,12 @@ abstract class BaseViewModel() : ViewModel() {
fun handleError(exception: Exception) {
Timber.d("handleError ${exception.message}")
}
fun parseEquipmentInfo(equipmentInfo: EquipmentInfo) {
GlobalData.appBaseUrl = equipmentInfo.appPackageUrl!!
GlobalData.sdkKey = equipmentInfo.arcsoftSdkKey!!
GlobalData.appId = equipmentInfo.arcsoftAppId!!
// GlobalData.activeKey = equipmentInfo.arcsoftActiveKey!!
GlobalData.restId = equipmentInfo.canteenId!!
}
}
@@ -0,0 +1,68 @@
package com.sw.platecabinet.viewmodel
import com.sw.inbound.utils.GsonUtils
import com.sw.inbound.utils.SPUtil
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.GlobalKey
import com.sw.platecabinet.model.response.EquipmentInfo
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import timber.log.Timber
import kotlin.jvm.java
/**
* 初始化的viewmodel
*/
class DeviceViewModel : BaseViewModel() {
private val _deviceInfoResult = MutableStateFlow<Boolean?>(null)
val deviceInfoResult: StateFlow<Boolean?> = _deviceInfoResult
/**
* 获取token
*/
fun getDeviceToken(deviceId: String = GlobalData.deviceId) {
launchWithLoading {
val response = repository.getDeviceToken(deviceId)
if (parseResponse(response)) {
val response1 = repository.getDeviceInfo(deviceId, response.result!!)
if (parseResponse(response1)) {
val equipmentInfo = response1.result
if (equipmentInfo == null) return@launchWithLoading
try {
parseEquipmentInfo(equipmentInfo)
SPUtil.getInstance()
.put(GlobalKey.KEY_EQUIPMENT_INFO, GsonUtils.toJson(equipmentInfo))
_deviceInfoResult.value = true
} catch (e: Exception) {
Timber.e(e)
}
}
}
}
}
/**
* 检查缓存数据
*/
fun checkEquipmentInfo(): Boolean {
val equipmentInfoStr = SPUtil.getInstance().get(GlobalKey.KEY_EQUIPMENT_INFO, "")
if (equipmentInfoStr == null) {
Timber.e("获取缓存设备信息失败")
return false
}
val equipmentInfo =
GsonUtils.fromJson<EquipmentInfo>(equipmentInfoStr, EquipmentInfo::class.java)
if (equipmentInfo == null) {
Timber.e("解析缓存设备信息失败")
return false
}
try {
parseEquipmentInfo(equipmentInfo)
return true
} catch (e: Exception) {
Timber.e(e)
return false
}
}
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item>
<shape android:shape="rectangle">
<solid android:color="#ff08C6DC" />
<corners android:radius="8dp" />
</shape>
</item>
</ripple>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="600dp"
android:height="1024dp">
<bitmap android:src="@drawable/bg"/>
</item>
<item
android:width="337dp"
android:height="322dp"
android:gravity="top|center_horizontal"
android:top="112dp">
<bitmap android:src="@drawable/img_init" android:scaleType="fitCenter"/>
</item>
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 999 KiB

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="337dp"
android:layout_height="322dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="112dp"
android:src="@drawable/img_init"
tools:ignore="ContentDescription"
android:visibility="invisible"/>
<TextView
android:id="@+id/btnInit"
android:layout_width="225dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="75dp"
android:background="@drawable/bg_init_button"
android:gravity="center"
android:padding="10dp"
android:text="设备初始化"
android:textColor="@color/white"
android:textSize="22sp"
android:textStyle="bold"
android:visibility="visible"
tools:ignore="HardcodedText" />
<Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:id="@+id/ivQrCode"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="37dp"
tools:ignore="ContentDescription"
tools:src="@mipmap/ic_logo512" />
</LinearLayout>
+3 -4
View File
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="40dp"
android:paddingHorizontal="24dp">
<TextView
@@ -11,11 +11,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingTop="20dp"
android:textColor="#FFCC99"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="2025年6月18日 星期三" />
<TextView
@@ -23,11 +22,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingTop="20dp"
android:textColor="#FFCC99"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvLeftDate"
app:layout_constraintBottom_toBottomOf="@id/tvLeftDate"
tools:text="14:02:39" />
</androidx.constraintlayout.widget.ConstraintLayout>

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

+1
View File
@@ -3,5 +3,6 @@
<style name="Base.Theme.SmartPlateCabinet" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
<item name="android:windowBackground">@drawable/bg_splash</item>
</style>
</resources>
+1
View File
@@ -4,6 +4,7 @@
<item name="android:windowFullscreen">true</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowBackground">@drawable/bg_splash</item>
</style>
<style name="Theme.SmartPlateCabinet" parent="Base.Theme.SmartPlateCabinet" />
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- <domain-config cleartextTrafficPermitted="true">-->
<!-- <domain includeSubdomains="true">vip.shuziweidao.com</domain>-->
<!-- <domain includeSubdomains="true">192.168.1.207</domain>-->
<!-- <domain includeSubdomains="true">device.shuziweidao.com</domain>-->
<!-- </domain-config>-->
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
+5
View File
@@ -23,7 +23,12 @@ timber = "5.0.1"
gson = "2.13.1"
hiltAndroid = "2.56.2"
core = "3.4.1"
androidCore = "3.3.0"
[libraries]
android-core = { module = "com.google.zxing:android-core", version.ref = "androidCore" }
core = { module = "com.google.zxing:core", version.ref = "core" }
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" }