Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d0fcd24b7 | ||
|
|
bb32ed84fe | ||
|
|
6a1a1f3c5c | ||
|
|
9311d13b90 | ||
|
|
143d24923b | ||
|
|
9a77733d24 |
+4
-6
@@ -1,15 +1,13 @@
|
|||||||
*.iml
|
*.iml
|
||||||
.gradle
|
.gradle
|
||||||
/local.properties
|
/local.properties
|
||||||
/.idea/caches
|
/.idea/
|
||||||
/.idea/libraries
|
|
||||||
/.idea/modules.xml
|
|
||||||
/.idea/workspace.xml
|
|
||||||
/.idea/navEditor.xml
|
|
||||||
/.idea/assetWizardSettings.xml
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
.cxx
|
.cxx
|
||||||
local.properties
|
local.properties
|
||||||
|
.claude/
|
||||||
|
app/debug/
|
||||||
|
app/release/
|
||||||
|
|||||||
Generated
-3
@@ -1,3 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="AndroidProjectSystem">
|
|
||||||
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<bytecodeTargetLevel target="21" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-18
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="deploymentTargetSelector">
|
|
||||||
<selectionStates>
|
|
||||||
<SelectionState runConfigName="app">
|
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
|
||||||
<DropdownSelection timestamp="2026-03-16T07:12:10.978585600Z">
|
|
||||||
<Target type="DEFAULT_BOOT">
|
|
||||||
<handle>
|
|
||||||
<DeviceId pluginId="Default" identifier="serial=192.168.1.115:5555;connection=8c23341a" />
|
|
||||||
</handle>
|
|
||||||
</Target>
|
|
||||||
</DropdownSelection>
|
|
||||||
<DialogSelection />
|
|
||||||
</SelectionState>
|
|
||||||
</selectionStates>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-13
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DeviceTable">
|
|
||||||
<option name="columnSorters">
|
|
||||||
<list>
|
|
||||||
<ColumnSorterState>
|
|
||||||
<option name="column" value="Name" />
|
|
||||||
<option name="order" value="ASCENDING" />
|
|
||||||
</ColumnSorterState>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-19
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-12
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="MaterialThemeProjectNewConfig">
|
|
||||||
<option name="metadata">
|
|
||||||
<MTProjectMetadataState>
|
|
||||||
<option name="migrated" value="true" />
|
|
||||||
<option name="pristineConfig" value="false" />
|
|
||||||
<option name="userId" value="4ab8791:19ce5d9ffb1:-7ffe" />
|
|
||||||
</MTProjectMetadataState>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-10
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectMigrations">
|
|
||||||
<option name="MigrateToGradleLocalJavaHome">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-9
@@ -1,9 +0,0 @@
|
|||||||
<project version="4">
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-17
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RunConfigurationProducerService">
|
|
||||||
<option name="ignoredProducers">
|
|
||||||
<set>
|
|
||||||
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -45,7 +45,6 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ui.InitActivity"
|
android:name=".ui.InitActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:screenOrientation="portrait"
|
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity">
|
tools:ignore="DiscouragedApi,LockedOrientationActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@@ -54,24 +53,29 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ui.HomeActivity"
|
<activity android:name=".ui.HomeActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.SelectDishActivity"
|
android:name=".ui.SelectDishActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.PrepareCookActivity"
|
android:name=".ui.PrepareCookActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.DishSamplingActivity"
|
android:name=".ui.DishSamplingActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.SamplingListActivity"
|
android:name=".ui.SamplingListActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
@@ -86,19 +90,26 @@
|
|||||||
<!-- tools:ignore="DiscouragedApi,LockedOrientationActivity" />-->
|
<!-- tools:ignore="DiscouragedApi,LockedOrientationActivity" />-->
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.FoodSearchActivity"
|
android:name=".ui.FoodSearchActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
<activity android:name="com.shuwei.dish.match.ui.DeviceConfigActivity" />
|
<activity android:name="com.shuwei.dish.match.ui.DeviceConfigActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash" />
|
||||||
<activity android:name="com.shuwei.dish.match.ui.SettingActivity"
|
<activity android:name="com.shuwei.dish.match.ui.SettingActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
<activity android:name="com.shuwei.dish.match.ui.SubmitFoodActivity" />
|
<activity android:name="com.shuwei.dish.match.ui.SubmitFoodActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash" />
|
||||||
<activity
|
<activity
|
||||||
android:name="com.shuwei.dish.match.ui.MasterScaleActivity"
|
android:name="com.shuwei.dish.match.ui.MasterScaleActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name="com.shuwei.dish.match.ui.SlaveActivity"
|
android:name="com.shuwei.dish.match.ui.SlaveActivity"
|
||||||
|
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||||
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="landscape"
|
android:screenOrientation="landscape"
|
||||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.shuwei.dish.match.base
|
package com.shuwei.dish.match.base
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
@@ -43,9 +44,16 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
// 提前隐藏系统栏,避免窗口创建时导航栏闪烁
|
||||||
|
hideSystemBars()
|
||||||
|
// 主设备竖屏,子设备横屏
|
||||||
|
requestedOrientation = if (GlobalData.deviceRole == DeviceRole.MASTER)
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
|
else
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||||
ActivityManager.addActivity(this)
|
ActivityManager.addActivity(this)
|
||||||
binding = ActivityBaseBinding.inflate(layoutInflater)
|
binding = ActivityBaseBinding.inflate(layoutInflater)
|
||||||
if (this !is InitActivity) {
|
if (this !is InitActivity || GlobalData.deviceRole == DeviceRole.SLAVE) {
|
||||||
binding.root.setBackgroundColor(ContextCompat.getColor(this, R.color.bg_color))
|
binding.root.setBackgroundColor(ContextCompat.getColor(this, R.color.bg_color))
|
||||||
}
|
}
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
@@ -129,7 +137,7 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
binding.tvLeftTime.text = arr[1]
|
binding.tvLeftTime.text = arr[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
private val updateTask = object : Runnable {
|
private val updateTask = object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
updateDateTime()
|
updateDateTime()
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.shuwei.dish.match.ui.InitActivity.Companion.TAG
|
|||||||
import com.shuwei.dish.match.utils.AppUtil
|
import com.shuwei.dish.match.utils.AppUtil
|
||||||
import com.shuwei.dish.match.utils.BootReceiver
|
import com.shuwei.dish.match.utils.BootReceiver
|
||||||
import com.shuwei.dish.match.utils.CrashHandler
|
import com.shuwei.dish.match.utils.CrashHandler
|
||||||
|
import com.shuwei.dish.match.utils.Weigher2
|
||||||
|
|
||||||
|
|
||||||
class BaseApp : Application() {
|
class BaseApp : Application() {
|
||||||
@@ -28,10 +29,13 @@ class BaseApp : Application() {
|
|||||||
GlobalData.deviceId = deviceId
|
GlobalData.deviceId = deviceId
|
||||||
|
|
||||||
// 根据设备 ID 判断角色:指定 ID 为主设备,其余为子设备
|
// 根据设备 ID 判断角色:指定 ID 为主设备,其余为子设备
|
||||||
GlobalData.deviceRole = if (deviceId == "8fc2ab34-2137-3112-acca-f884ea8736d4") {
|
// 主设备是/dev/ttyS7,子设备是/dev/ttyS4
|
||||||
DeviceRole.MASTER
|
if (deviceId == "8fc2ab34-2137-3112-acca-f884ea8736d4") {
|
||||||
|
GlobalData.deviceRole = DeviceRole.MASTER
|
||||||
|
Weigher2.setDevicePort("/dev/ttyS7")
|
||||||
} else {
|
} else {
|
||||||
DeviceRole.SLAVE
|
GlobalData.deviceRole = DeviceRole.SLAVE
|
||||||
|
Weigher2.setDevicePort("/dev/ttyS4")
|
||||||
}
|
}
|
||||||
Log.d(TAG, "设备角色: ${GlobalData.deviceRole}")
|
Log.d(TAG, "设备角色: ${GlobalData.deviceRole}")
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ import android.content.Context
|
|||||||
import android.net.nsd.NsdManager
|
import android.net.nsd.NsdManager
|
||||||
import android.net.nsd.NsdServiceInfo
|
import android.net.nsd.NsdServiceInfo
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import java.util.LinkedList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mDNS 设备发现管理器(仅主设备运行)
|
* mDNS 设备发现管理器(仅主设备运行)
|
||||||
* 持续扫描局域网,发现或丢失 DishMatch 子设备时通过回调通知连接管理器
|
* 持续扫描局域网,发现或丢失 DishMatch 子设备时通过回调通知连接管理器
|
||||||
|
*
|
||||||
|
* 注意:Android NsdManager.resolveService 不支持并发调用,多台子设备同时被发现时
|
||||||
|
* 会报 FAILURE_ALREADY_ACTIVE(3) 导致解析失败。此处使用串行队列逐一解析。
|
||||||
*/
|
*/
|
||||||
class MdnsDiscoveryManager(private val context: Context) {
|
class MdnsDiscoveryManager(private val context: Context) {
|
||||||
|
|
||||||
@@ -22,6 +26,11 @@ class MdnsDiscoveryManager(private val context: Context) {
|
|||||||
private var discoveryListener: NsdManager.DiscoveryListener? = null
|
private var discoveryListener: NsdManager.DiscoveryListener? = null
|
||||||
private var isDiscovering = false
|
private var isDiscovering = false
|
||||||
|
|
||||||
|
/** 待解析队列,串行处理避免并发解析失败 */
|
||||||
|
private val resolveQueue = LinkedList<NsdServiceInfo>()
|
||||||
|
@Volatile
|
||||||
|
private var isResolving = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发现新设备时的回调:(deviceId, host, port)
|
* 发现新设备时的回调:(deviceId, host, port)
|
||||||
*/
|
*/
|
||||||
@@ -62,7 +71,7 @@ class MdnsDiscoveryManager(private val context: Context) {
|
|||||||
// 只处理 DishMatch 服务
|
// 只处理 DishMatch 服务
|
||||||
if (!service.serviceName.startsWith("DishMatch-")) return
|
if (!service.serviceName.startsWith("DishMatch-")) return
|
||||||
Log.d(TAG, "发现设备: ${service.serviceName}")
|
Log.d(TAG, "发现设备: ${service.serviceName}")
|
||||||
resolveService(service)
|
enqueueResolve(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceLost(service: NsdServiceInfo) {
|
override fun onServiceLost(service: NsdServiceInfo) {
|
||||||
@@ -87,18 +96,45 @@ class MdnsDiscoveryManager(private val context: Context) {
|
|||||||
nsdManager.resolveService(service, object : NsdManager.ResolveListener {
|
nsdManager.resolveService(service, object : NsdManager.ResolveListener {
|
||||||
override fun onResolveFailed(info: NsdServiceInfo, errorCode: Int) {
|
override fun onResolveFailed(info: NsdServiceInfo, errorCode: Int) {
|
||||||
Log.e(TAG, "解析设备地址失败: ${info.serviceName}, errorCode=$errorCode")
|
Log.e(TAG, "解析设备地址失败: ${info.serviceName}, errorCode=$errorCode")
|
||||||
|
// 解析结束(失败),继续处理队列中下一个
|
||||||
|
processNextResolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceResolved(info: NsdServiceInfo) {
|
override fun onServiceResolved(info: NsdServiceInfo) {
|
||||||
val deviceId = info.serviceName.removePrefix("DishMatch-")
|
val deviceId = info.serviceName.removePrefix("DishMatch-")
|
||||||
val host = info.host?.hostAddress ?: return
|
val host = info.host?.hostAddress ?: run {
|
||||||
|
processNextResolve()
|
||||||
|
return
|
||||||
|
}
|
||||||
val port = info.port
|
val port = info.port
|
||||||
Log.d(TAG, "设备地址已解析: $deviceId -> $host:$port")
|
Log.d(TAG, "设备地址已解析: $deviceId -> $host:$port")
|
||||||
onDeviceFound?.invoke(deviceId, host, port)
|
onDeviceFound?.invoke(deviceId, host, port)
|
||||||
|
// 解析结束(成功),继续处理队列中下一个
|
||||||
|
processNextResolve()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 将待解析服务加入队列,若当前无解析任务则立即开始 */
|
||||||
|
@Synchronized
|
||||||
|
private fun enqueueResolve(service: NsdServiceInfo) {
|
||||||
|
resolveQueue.add(service)
|
||||||
|
if (!isResolving) {
|
||||||
|
processNextResolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 从队列取出下一个服务进行解析 */
|
||||||
|
@Synchronized
|
||||||
|
private fun processNextResolve() {
|
||||||
|
val next = resolveQueue.poll() ?: run {
|
||||||
|
isResolving = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isResolving = true
|
||||||
|
resolveService(next)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停止扫描,在应用退出时调用
|
* 停止扫描,在应用退出时调用
|
||||||
*/
|
*/
|
||||||
@@ -112,5 +148,9 @@ class MdnsDiscoveryManager(private val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
discoveryListener = null
|
discoveryListener = null
|
||||||
|
synchronized(this) {
|
||||||
|
resolveQueue.clear()
|
||||||
|
isResolving = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ object ScaleServiceManager {
|
|||||||
get() = wsServer?.onConnectionChanged
|
get() = wsServer?.onConnectionChanged
|
||||||
set(value) { wsServer?.onConnectionChanged = value }
|
set(value) { wsServer?.onConnectionChanged = value }
|
||||||
|
|
||||||
|
/** 当前是否有主设备连接(仅子设备使用) */
|
||||||
|
val isMasterConnected: Boolean
|
||||||
|
get() = wsServer?.isConnected == true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动所有秤服务,在 Application.onCreate() 中调用
|
* 启动所有秤服务,在 Application.onCreate() 中调用
|
||||||
*/
|
*/
|
||||||
@@ -63,7 +67,7 @@ object ScaleServiceManager {
|
|||||||
Log.d(TAG, "启动秤服务, deviceId=$deviceId, role=$role")
|
Log.d(TAG, "启动秤服务, deviceId=$deviceId, role=$role")
|
||||||
|
|
||||||
// 所有设备:启动 WebSocket 服务端 + mDNS 注册
|
// 所有设备:启动 WebSocket 服务端 + mDNS 注册
|
||||||
wsServer = ScaleWebSocketServer(deviceId).also { it.start() }
|
wsServer = ScaleWebSocketServer(deviceId, context).also { it.start() }
|
||||||
mdnsRegister = MdnsRegisterManager(context).also { it.register(deviceId) }
|
mdnsRegister = MdnsRegisterManager(context).also { it.register(deviceId) }
|
||||||
|
|
||||||
if (role == DeviceRole.MASTER) {
|
if (role == DeviceRole.MASTER) {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.shuwei.dish.match.scale
|
package com.shuwei.dish.match.scale
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
import com.shuwei.dish.match.utils.NetworkUtil
|
||||||
import com.shuwei.dish.match.utils.WeightUtil
|
import com.shuwei.dish.match.utils.WeightUtil
|
||||||
import org.java_websocket.WebSocket
|
import org.java_websocket.WebSocket
|
||||||
import org.java_websocket.handshake.ClientHandshake
|
import org.java_websocket.handshake.ClientHandshake
|
||||||
@@ -12,7 +14,7 @@ import java.net.InetSocketAddress
|
|||||||
* 秤数据 WebSocket 服务端(主设备和子设备均运行)
|
* 秤数据 WebSocket 服务端(主设备和子设备均运行)
|
||||||
* 监听 WeightUtil 回调,将本机秤数据实时推送给所有已连接的主设备客户端
|
* 监听 WeightUtil 回调,将本机秤数据实时推送给所有已连接的主设备客户端
|
||||||
*/
|
*/
|
||||||
class ScaleWebSocketServer(private val deviceId: String) {
|
class ScaleWebSocketServer(private val deviceId: String, private val context: Context) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ScaleWebSocketServer"
|
private const val TAG = "ScaleWebSocketServer"
|
||||||
@@ -26,6 +28,10 @@ class ScaleWebSocketServer(private val deviceId: String) {
|
|||||||
/** 主设备连接状态变化回调:true=已连接,false=已断开;在主线程外调用,需自行切换线程 */
|
/** 主设备连接状态变化回调:true=已连接,false=已断开;在主线程外调用,需自行切换线程 */
|
||||||
var onConnectionChanged: ((connected: Boolean) -> Unit)? = null
|
var onConnectionChanged: ((connected: Boolean) -> Unit)? = null
|
||||||
|
|
||||||
|
/** 当前是否有主设备连接 */
|
||||||
|
val isConnected: Boolean
|
||||||
|
get() = server?.connections?.isNotEmpty() == true
|
||||||
|
|
||||||
/** 每个秤地址的最近一次推送时间,用于节流 */
|
/** 每个秤地址的最近一次推送时间,用于节流 */
|
||||||
private val lastPushTime = mutableMapOf<Int, Long>()
|
private val lastPushTime = mutableMapOf<Int, Long>()
|
||||||
|
|
||||||
@@ -53,7 +59,8 @@ class ScaleWebSocketServer(private val deviceId: String) {
|
|||||||
address = address,
|
address = address,
|
||||||
weight = weight,
|
weight = weight,
|
||||||
state = state,
|
state = state,
|
||||||
ts = now
|
ts = now,
|
||||||
|
ip = NetworkUtil.getLocalIpAddress(context)
|
||||||
)
|
)
|
||||||
latestData[address] = data
|
latestData[address] = data
|
||||||
broadcast(gson.toJson(data))
|
broadcast(gson.toJson(data))
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class UdpBroadcastReceiver {
|
|||||||
|
|
||||||
private fun listenLoop() {
|
private fun listenLoop() {
|
||||||
try {
|
try {
|
||||||
socket = DatagramSocket(UdpBroadcastSender.BROADCAST_PORT)
|
socket = DatagramSocket(UdpBroadcastSender.BROADCAST_PORT).also { it.broadcast = true }
|
||||||
val buf = ByteArray(BUFFER_SIZE)
|
val buf = ByteArray(BUFFER_SIZE)
|
||||||
while (running) {
|
while (running) {
|
||||||
val packet = DatagramPacket(buf, buf.size)
|
val packet = DatagramPacket(buf, buf.size)
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
package com.shuwei.dish.match.ui
|
package com.shuwei.dish.match.ui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.os.SystemClock
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.animation.RotateAnimation
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.core.graphics.toColorInt
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.shuwei.dish.match.base.BaseActivity
|
import com.shuwei.dish.match.base.BaseActivity
|
||||||
@@ -11,19 +18,15 @@ import com.shuwei.dish.match.base.DeviceRole
|
|||||||
import com.shuwei.dish.match.base.GlobalData
|
import com.shuwei.dish.match.base.GlobalData
|
||||||
import com.shuwei.dish.match.databinding.ActivityInitBinding
|
import com.shuwei.dish.match.databinding.ActivityInitBinding
|
||||||
import com.shuwei.dish.match.db.AppRepository
|
import com.shuwei.dish.match.db.AppRepository
|
||||||
import com.shuwei.dish.match.http.UrlConfig
|
|
||||||
import com.shuwei.dish.match.utils.AppUtil
|
import com.shuwei.dish.match.utils.AppUtil
|
||||||
import com.shuwei.dish.match.utils.QRCodeUtil
|
import com.shuwei.dish.match.utils.NetworkUtils
|
||||||
import com.shuwei.dish.match.utils.SpTool
|
import com.shuwei.dish.match.utils.SpTool
|
||||||
import com.shuwei.dish.match.utils.WeightUtil
|
|
||||||
import com.shuwei.dish.match.utils.Weigher2
|
import com.shuwei.dish.match.utils.Weigher2
|
||||||
import com.shuwei.dish.match.utils.ext.dp
|
import com.shuwei.dish.match.utils.WeightUtil
|
||||||
import com.shuwei.dish.match.utils.ext.startActivity
|
import com.shuwei.dish.match.utils.ext.startActivity
|
||||||
import com.shuwei.dish.match.utils.ext.toObject
|
|
||||||
import com.shuwei.dish.match.viewmodel.AppViewModel
|
import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||||
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.flow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class InitActivity : BaseActivity() {
|
class InitActivity : BaseActivity() {
|
||||||
@@ -33,10 +36,13 @@ class InitActivity : BaseActivity() {
|
|||||||
|
|
||||||
private lateinit var binding: ActivityInitBinding
|
private lateinit var binding: ActivityInitBinding
|
||||||
private lateinit var appViewModel: AppViewModel
|
private lateinit var appViewModel: AppViewModel
|
||||||
|
private var startTime = 0L // 倒计时开始时间
|
||||||
|
private var lastNetworkCheckTime = 0L // 上次检测网络的时间
|
||||||
|
|
||||||
@SuppressLint("HardwareIds")
|
@SuppressLint("HardwareIds")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
addBackKeyListener()
|
||||||
statusBarDarkFont(enable = true)
|
statusBarDarkFont(enable = true)
|
||||||
// useBackground(false)
|
// useBackground(false)
|
||||||
binding = ActivityInitBinding.inflate(layoutInflater)
|
binding = ActivityInitBinding.inflate(layoutInflater)
|
||||||
@@ -48,55 +54,18 @@ class InitActivity : BaseActivity() {
|
|||||||
setHeaderBgVisible(false)
|
setHeaderBgVisible(false)
|
||||||
BaseApp.appVersion = AppUtil.getAppVersionCode(this).toString()
|
BaseApp.appVersion = AppUtil.getAppVersionCode(this).toString()
|
||||||
|
|
||||||
// 获取 ANDROID_ID
|
|
||||||
// var androidId = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
|
|
||||||
// androidId = "39a7abdd06b3c7ab"
|
|
||||||
// BaseApp.deviceId = androidId
|
|
||||||
// SpTool.put(SpTool.DEVICE_ID, androidId)
|
|
||||||
// BaseApp.configUrl = UrlConfig.BASE_URL
|
|
||||||
BaseApp.canteenId = "0"
|
BaseApp.canteenId = "0"
|
||||||
// // TODO: 以上保存deviceId用于临时使用,后续改为下面注释方式
|
|
||||||
|
|
||||||
// var deviceId = AppUtil.getUDID(this)
|
|
||||||
// Log.d(TAG, "onCreate: deviceId=$deviceId")
|
|
||||||
//// deviceId = "39a7abdd06b3c7ab"
|
|
||||||
// deviceId = "3ea47dc0-3cf0-3c2f-909c-265a9a65572e"
|
|
||||||
//// deviceId = "6ce7cd59-b875-38b2-b73d-88a570be3212"
|
|
||||||
//
|
|
||||||
// BaseApp.deviceId = deviceId
|
|
||||||
//
|
|
||||||
// SpTool.put(SpTool.DEVICE_ID, deviceId)
|
|
||||||
// val deviceConfigCache = SpTool.getString(SpTool.DEVICE_CONFIG_CACHE)
|
|
||||||
// val checkResult = checkConfigData(deviceConfigCache)
|
|
||||||
// if (checkResult.not()) {
|
|
||||||
// binding.ivQrCode.visible()
|
|
||||||
// binding.btnInit.visible()
|
|
||||||
// //进行初始化操作
|
|
||||||
// initConfig()
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// binding.ivQrCode.invisible()
|
|
||||||
// binding.btnInit.invisible()
|
|
||||||
|
|
||||||
initViewModel()
|
initViewModel()
|
||||||
// 若有保存的串口配置则先应用(子设备串口可能与主设备不同)
|
|
||||||
// val savedPort = SpTool.getString(SpTool.SCALE_DEVICE_PORT, "")
|
|
||||||
// if (savedPort.isNotEmpty()) {
|
|
||||||
// Weigher2.setDevicePort(savedPort)
|
|
||||||
// }
|
|
||||||
// TODO: 测试不同的串口配置---------------------2、5、3
|
|
||||||
Weigher2.setDevicePort(
|
|
||||||
if (GlobalData.deviceId == "8fc2ab34-2137-3112-acca-f884ea8736d4") {
|
|
||||||
"/dev/ttyS7"
|
|
||||||
} else {
|
|
||||||
"/dev/ttyS4"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
WeightUtil.init()
|
WeightUtil.init()
|
||||||
WeightUtil.getWeight()
|
WeightUtil.getWeight()
|
||||||
WeightUtil.startContinuousRead()
|
WeightUtil.startContinuousRead()
|
||||||
countDown()
|
|
||||||
|
initViews()
|
||||||
|
val dpi = resources.displayMetrics.density
|
||||||
|
val metrics = resources.displayMetrics.toString()
|
||||||
|
Log.d(TAG, "dpi=$dpi, $metrics")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initViewModel() {
|
private fun initViewModel() {
|
||||||
@@ -106,24 +75,27 @@ class InitActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startNextPage() {
|
private fun startNextPage() {
|
||||||
// 子设备:直接进入小屏专属页面,不走原有大屏业务流程
|
lifecycleScope.launch {
|
||||||
if (GlobalData.deviceRole == DeviceRole.SLAVE) {
|
delay(2000)
|
||||||
startActivity<SlaveActivity>()
|
// 子设备:直接进入小屏专属页面,不走原有大屏业务流程
|
||||||
return
|
if (GlobalData.deviceRole == DeviceRole.SLAVE) {
|
||||||
}
|
startActivity<SlaveActivity>()
|
||||||
// 主设备:走原有路由逻辑
|
return@launch
|
||||||
val launchPageType = SpTool.getInt(SpTool.LAUNCH_PAGE_TYPE, -1)
|
|
||||||
when (launchPageType) {
|
|
||||||
0 -> {
|
|
||||||
startActivity<SelectDishActivity>()
|
|
||||||
}
|
}
|
||||||
|
// 主设备:走原有路由逻辑
|
||||||
|
val launchPageType = SpTool.getInt(SpTool.LAUNCH_PAGE_TYPE, -1)
|
||||||
|
when (launchPageType) {
|
||||||
|
0 -> {
|
||||||
|
startActivity<SelectDishActivity>()
|
||||||
|
}
|
||||||
|
|
||||||
1 -> {
|
1 -> {
|
||||||
goSampling()
|
goSampling()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
startActivity<HomeActivity>()
|
startActivity<HomeActivity>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,112 +105,152 @@ class InitActivity : BaseActivity() {
|
|||||||
if (it.isEmpty()) {
|
if (it.isEmpty()) {
|
||||||
//无调料信息打开采样历史列表页面,点击设置配置调料信息
|
//无调料信息打开采样历史列表页面,点击设置配置调料信息
|
||||||
startActivity<SamplingListActivity>()
|
startActivity<SamplingListActivity>()
|
||||||
// finish()
|
|
||||||
return@loadSeasoning
|
return@loadSeasoning
|
||||||
}
|
}
|
||||||
appViewModel.countCookFood(cookMode = 1) { count ->
|
appViewModel.countCookFood(cookMode = 1) { count ->
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
//有烹饪中数据打开采样历史列表页面
|
//有烹饪中数据打开采样历史列表页面
|
||||||
startActivity<SamplingListActivity>()
|
startActivity<SamplingListActivity>()
|
||||||
// finish()
|
|
||||||
return@countCookFood
|
return@countCookFood
|
||||||
}
|
}
|
||||||
//无烹饪数据打开新增采样页面
|
//无烹饪数据打开新增采样页面
|
||||||
startActivity<DishSamplingActivity> {
|
startActivity<DishSamplingActivity> {
|
||||||
putExtra(DishSamplingActivity.PAGE_FROM, DishSamplingActivity.HOME)
|
putExtra(DishSamplingActivity.PAGE_FROM, DishSamplingActivity.HOME)
|
||||||
}
|
}
|
||||||
// finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun countDown() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
flow {
|
|
||||||
(2 downTo 1).forEach {
|
|
||||||
delay(1000)
|
|
||||||
emit(it)
|
|
||||||
}
|
|
||||||
}.collect {
|
|
||||||
// 倒计时结束执行跳转
|
|
||||||
if (it == 1) {
|
|
||||||
startNextPage()
|
|
||||||
//保留初始化页面,不关闭
|
|
||||||
// finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// private fun initConfig() {
|
|
||||||
// binding.ivQrCode.setImageBitmap(
|
|
||||||
// QRCodeUtil.generateQRCode(
|
|
||||||
// content = BaseApp.deviceId ?: "",
|
|
||||||
// size = 200.dp
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// binding.btnInit.setOnClickListener {
|
|
||||||
//// HttpUtil.loopGetToken = false
|
|
||||||
//// getDeviceConfig()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private fun getDeviceConfig() {
|
|
||||||
// val tokenUrl =
|
|
||||||
// "${UrlConfig.DEVICE_TOKEN}?qrcodeId=${BaseApp.deviceId}&appVersion=${BaseApp.appVersion}"
|
|
||||||
// HttpUtil.get(url = tokenUrl, doSuccess = { token ->
|
|
||||||
// Log.d(TAG, "initConfig: $token")
|
|
||||||
// getConfig(token.toString())
|
|
||||||
// }, doFailure = { code, msg ->
|
|
||||||
// Log.d(TAG, "initConfig: $code,$msg")
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private fun getConfig(token: String) {
|
|
||||||
// val deviceConfigUrl =
|
|
||||||
// "${UrlConfig.DEVICE_CONFIG}?equipmentCode=${BaseApp.deviceId}&&appVersion=${BaseApp.appVersion}"
|
|
||||||
// HttpUtil.get(
|
|
||||||
// url = deviceConfigUrl, header = mutableMapOf(
|
|
||||||
// "X-Access-Token" to token
|
|
||||||
// ), doSuccess = {
|
|
||||||
// Log.d(TAG, "getDeviceConfig: $it")
|
|
||||||
// val data = it.toJsonString()
|
|
||||||
// val checkResult = checkConfigData(data)
|
|
||||||
// if (checkResult.not()) {
|
|
||||||
// toast("初始化设备失败,请稍后重试")
|
|
||||||
// return@get
|
|
||||||
// }
|
|
||||||
// HttpUtil.loopGetToken = true
|
|
||||||
// SpTool.put(SpTool.DEVICE_CONFIG_CACHE, data)
|
|
||||||
// startActivity<HomeActivity>()
|
|
||||||
//// finish()
|
|
||||||
// }, doFailure = { code, msg ->
|
|
||||||
// Log.d(TAG, "getDeviceConfig: $code,$msg")
|
|
||||||
// toast("初始化设备失败,请稍后重试,code=${code},msg=${msg}")
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
data class DeviceConfigBean(
|
|
||||||
var appPackageUrl: String? = null,
|
|
||||||
var canteenId: String? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
// private fun checkConfigData(data: String): Boolean {
|
|
||||||
// if (data.isBlank()) {
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// val config = data.toObject<DeviceConfigBean?>()
|
|
||||||
// if (config == null) {
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// BaseApp.configUrl = config.appPackageUrl ?: ""
|
|
||||||
// BaseApp.canteenId = config.canteenId ?: ""
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
WeightUtil.stopContinuousRead()
|
WeightUtil.stopContinuousRead()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化控件事件
|
||||||
|
*/
|
||||||
|
private fun initViews() {
|
||||||
|
// 连接网络按钮点击事件
|
||||||
|
binding.btnConnectNetwork.setOnClickListener {
|
||||||
|
openNetworkSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动加载动画 - 持续旋转
|
||||||
|
startLoadingAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动加载动画 - ImageView 持续旋转
|
||||||
|
*/
|
||||||
|
private fun startLoadingAnimation() {
|
||||||
|
val rotateAnimation = RotateAnimation(
|
||||||
|
0f, 360f,
|
||||||
|
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
|
||||||
|
RotateAnimation.RELATIVE_TO_SELF, 0.5f
|
||||||
|
).apply {
|
||||||
|
duration = 1200 // 旋转周期 1.2 秒
|
||||||
|
repeatCount = RotateAnimation.INFINITE // 无限循环
|
||||||
|
repeatMode = RotateAnimation.RESTART
|
||||||
|
}
|
||||||
|
binding.ivLoading.startAnimation(rotateAnimation)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (NetworkUtils.isNetworkConnected(this)) {
|
||||||
|
startNextPage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
startCountdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
// 页面不可见时停止倒计时
|
||||||
|
handler.removeCallbacksAndMessages(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动 60 秒倒计时
|
||||||
|
*/
|
||||||
|
private fun startCountdown() {
|
||||||
|
startTime = SystemClock.elapsedRealtime()
|
||||||
|
lastNetworkCheckTime = 0
|
||||||
|
// binding.llNetwork.setBackgroundColor(Color.TRANSPARENT)
|
||||||
|
binding.llLoading.visibility = android.view.View.VISIBLE
|
||||||
|
binding.llNetworkButton.visibility = android.view.View.GONE
|
||||||
|
binding.tvCountdown.text = "60秒"
|
||||||
|
scheduleCountdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时更新倒计时
|
||||||
|
* 使用 SystemClock.elapsedRealtime() 确保精确计时
|
||||||
|
*/
|
||||||
|
private fun scheduleCountdown() {
|
||||||
|
handler.postDelayed({
|
||||||
|
val elapsedTime = SystemClock.elapsedRealtime() - startTime
|
||||||
|
val remainingTime = 60 - (elapsedTime / 1000).toInt()
|
||||||
|
val currentNetworkCheckTime = (elapsedTime / 1000).toInt()
|
||||||
|
|
||||||
|
// 每 10 秒检测一次网络
|
||||||
|
if (currentNetworkCheckTime > 0 && currentNetworkCheckTime % 10 == 0 && currentNetworkCheckTime != lastNetworkCheckTime.toInt()) {
|
||||||
|
lastNetworkCheckTime = currentNetworkCheckTime.toLong()
|
||||||
|
checkNetworkConnection()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 倒计时未结束,继续更新 UI
|
||||||
|
if (remainingTime > 0) {
|
||||||
|
binding.tvCountdown.text = "${remainingTime}秒"
|
||||||
|
scheduleCountdown()
|
||||||
|
} else {
|
||||||
|
// 倒计时结束,最后检测一次网络
|
||||||
|
if (NetworkUtils.isNetworkConnected(this)) {
|
||||||
|
startNextPage()
|
||||||
|
} else {
|
||||||
|
// 网络未连接,显示"连接网络"按钮
|
||||||
|
showNetworkButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100) // 每 100ms 检查一次,确保精确性
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测网络连接
|
||||||
|
*/
|
||||||
|
private fun checkNetworkConnection() {
|
||||||
|
if (NetworkUtils.isNetworkConnected(this)) {
|
||||||
|
// 网络连接成功,停止倒计时并跳转到 HomeActivity
|
||||||
|
handler.removeCallbacksAndMessages(null)
|
||||||
|
startNextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示"连接网络"按钮
|
||||||
|
*/
|
||||||
|
private fun showNetworkButton() {
|
||||||
|
// binding.llNetwork.setBackgroundColor("#5C77F7".toColorInt())
|
||||||
|
binding.llLoading.visibility = android.view.View.GONE
|
||||||
|
binding.llNetworkButton.visibility = android.view.View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开系统网络设置页面
|
||||||
|
*/
|
||||||
|
private fun openNetworkSettings() {
|
||||||
|
val intent = Intent(android.provider.Settings.ACTION_WIFI_SETTINGS)
|
||||||
|
startActivity(intent) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addBackKeyListener() {
|
||||||
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
// 禁用返回键,不执行任何操作
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import android.view.LayoutInflater
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
import com.shuwei.dish.match.base.BaseActivity
|
import com.shuwei.dish.match.base.BaseActivity
|
||||||
import com.shuwei.dish.match.base.GlobalData
|
import com.shuwei.dish.match.base.GlobalData
|
||||||
import com.shuwei.dish.match.databinding.ActivitySlaveBinding
|
import com.shuwei.dish.match.databinding.ActivitySlaveBinding
|
||||||
@@ -44,9 +45,21 @@ class SlaveActivity : BaseActivity() {
|
|||||||
binding.rvScaleList.itemAnimator = null // 关闭默认动画,避免数据频繁更新时出现闪烁错乱
|
binding.rvScaleList.itemAnimator = null // 关闭默认动画,避免数据频繁更新时出现闪烁错乱
|
||||||
binding.rvScaleList.adapter = adapter
|
binding.rvScaleList.adapter = adapter
|
||||||
|
|
||||||
updateMasterStatus(false)
|
updateMasterStatus(ScaleServiceManager.isMasterConnected)
|
||||||
listenLocalScales()
|
listenLocalScales()
|
||||||
listenMasterConnection()
|
listenMasterConnection()
|
||||||
|
addBackKeyListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用返回键,防止退回 InitActivity 后重复打开本页
|
||||||
|
*/
|
||||||
|
private fun addBackKeyListener() {
|
||||||
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
// 禁用返回键,不执行任何操作
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.shuwei.dish.match.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络连接检测工具类
|
||||||
|
* 提供检测设备网络连接状态的功能
|
||||||
|
*/
|
||||||
|
object NetworkUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测设备是否连接到网络
|
||||||
|
* @param context 应用上下文
|
||||||
|
* @return true 表示已连接网络,false 表示未连接
|
||||||
|
*/
|
||||||
|
fun isNetworkConnected(context: Context): Boolean {
|
||||||
|
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
val network = connectivityManager.activeNetwork ?: return false
|
||||||
|
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
|
||||||
|
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import android.util.Log
|
|||||||
import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace
|
import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace
|
||||||
//import com.aithings.Weigher
|
//import com.aithings.Weigher
|
||||||
import com.wabon.wbintelligenthardwaresdk.api.SensorScale
|
import com.wabon.wbintelligenthardwaresdk.api.SensorScale
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
typealias WeightCallback = (address: Int, state: Int, weight: Double) -> Unit
|
typealias WeightCallback = (address: Int, state: Int, weight: Double) -> Unit
|
||||||
|
|
||||||
@@ -17,8 +18,7 @@ object WeightUtil {
|
|||||||
const val STATE_OVER_WEIGHT = SensorScale.STATE_OVER_WEIGHT
|
const val STATE_OVER_WEIGHT = SensorScale.STATE_OVER_WEIGHT
|
||||||
|
|
||||||
var isConnected = false
|
var isConnected = false
|
||||||
var weightFuncMap: MutableMap<String, WeightCallback?>? =
|
val weightFuncMap: ConcurrentHashMap<String, WeightCallback?> = ConcurrentHashMap()
|
||||||
null
|
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
Weigher2.init()
|
Weigher2.init()
|
||||||
@@ -38,7 +38,7 @@ object WeightUtil {
|
|||||||
}
|
}
|
||||||
val useWeight = (weight*1000).roundedOneDecimalPlace()
|
val useWeight = (weight*1000).roundedOneDecimalPlace()
|
||||||
Log.d(TAG, "readWeight, address=$address,state=$stateStr, weight=$useWeight")
|
Log.d(TAG, "readWeight, address=$address,state=$stateStr, weight=$useWeight")
|
||||||
weightFuncMap?.forEach { (key, value) ->
|
weightFuncMap.forEach { (key, value) ->
|
||||||
value?.invoke(address, state, useWeight)
|
value?.invoke(address, state, useWeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,18 +82,15 @@ object WeightUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeWeightListener(weightKey: String){
|
fun removeWeightListener(weightKey: String) {
|
||||||
weightFuncMap?.remove(weightKey)
|
weightFuncMap.remove(weightKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addWeightListener(
|
fun addWeightListener(
|
||||||
weightKey: String,
|
weightKey: String,
|
||||||
getWeight: WeightCallback = { _, _, _ -> }
|
getWeight: WeightCallback = { _, _, _ -> }
|
||||||
) {
|
) {
|
||||||
if (weightFuncMap == null) {
|
weightFuncMap[weightKey] = getWeight
|
||||||
weightFuncMap = mutableMapOf()
|
|
||||||
}
|
|
||||||
weightFuncMap?.put(weightKey, getWeight)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 横屏专用启动背景,适配子设备 800×480 屏幕 -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- 背景色铺满全屏 -->
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/bg_color"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<!-- 图片居中显示,适配横屏比例 -->
|
||||||
|
<item
|
||||||
|
android:width="200dp"
|
||||||
|
android:height="190dp"
|
||||||
|
android:gravity="center">
|
||||||
|
<bitmap android:src="@drawable/img_init" android:scaleType="fitCenter"/>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#4ECDC4" />
|
||||||
|
<corners android:radius="12dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="2dp"
|
||||||
|
android:color="#2BA39F" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="80dp"
|
||||||
|
android:height="80dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<!-- 网络断开的图标 -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF6B6B"
|
||||||
|
android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2c-4.42,-4.42 -11.58,-4.42 -16,0zM9,17h6v2h-6z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="ring"
|
||||||
|
android:innerRadiusRatio="3"
|
||||||
|
android:thicknessRatio="8"
|
||||||
|
android:useLevel="false">
|
||||||
|
<gradient
|
||||||
|
android:type="sweep"
|
||||||
|
android:startColor="#FF6B6B"
|
||||||
|
android:centerColor="#4ECDC4"
|
||||||
|
android:endColor="#FF6B6B"
|
||||||
|
android:angle="0" />
|
||||||
|
</shape>
|
||||||
|
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 横屏 800×480 专用布局,View ID 与 activity_init.xml 完全一致,供子设备使用 -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/bg_color">
|
||||||
|
|
||||||
|
<!-- 主内容区:水平居中排列加载区和网络错误区 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llNetwork"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<!-- 加载动画容器 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llLoading"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<!-- 加载动画 -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivLoading"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:src="@drawable/loading_spinner"
|
||||||
|
android:contentDescription="加载中" />
|
||||||
|
|
||||||
|
<!-- 倒计时文字 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCountdown"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="60秒"
|
||||||
|
android:textSize="32sp"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginTop="16dp" />
|
||||||
|
|
||||||
|
<!-- 提示文字 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="网络连接检测中,请稍后……"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="#555555"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 连接网络按钮容器 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llNetworkButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<!-- 网络错误图标 -->
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:src="@drawable/ic_network_error"
|
||||||
|
android:contentDescription="网络连接失败"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- 连接失败提示 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="网络连接失败"
|
||||||
|
android:textSize="28sp"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<!-- 连接网络按钮 -->
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnConnectNetwork"
|
||||||
|
android:layout_width="260dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:text="连接网络"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:background="@drawable/btn_connect_network"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 以下 View 在此布局中不使用,保留 ID 确保 ActivityInitBinding.bind() 不崩溃 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/btnInit"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivQrCode"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -1,51 +1,145 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:layout_width="450dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="430dp"
|
|
||||||
android:layout_marginStart="50dp"
|
|
||||||
android:layout_marginTop="250dp"
|
|
||||||
android:layout_marginEnd="50dp"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:src="@drawable/img_init"
|
|
||||||
tools:ignore="ContentDescription"
|
|
||||||
android:visibility="invisible"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/btnInit"
|
|
||||||
android:layout_width="300dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:orientation="vertical">
|
||||||
android:layout_marginTop="160dp"
|
|
||||||
android:background="@drawable/bg_init_button"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:text="设备初始化"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="30sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:ignore="HardcodedText"
|
|
||||||
android:visibility="invisible"/>
|
|
||||||
|
|
||||||
<Space
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="450dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="430dp"
|
||||||
android:layout_weight="1"/>
|
android:layout_marginStart="50dp"
|
||||||
|
android:layout_marginTop="250dp"
|
||||||
|
android:layout_marginEnd="50dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:src="@drawable/img_init"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:id="@+id/ivQrCode"
|
android:id="@+id/btnInit"
|
||||||
android:layout_width="200dp"
|
android:layout_width="300dp"
|
||||||
android:layout_height="200dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal|bottom"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_marginBottom="50dp"
|
android:layout_marginTop="160dp"
|
||||||
tools:src="@mipmap/ic_logo1024"
|
android:background="@drawable/bg_init_button"
|
||||||
tools:ignore="ContentDescription"
|
android:gravity="center"
|
||||||
android:visibility="invisible"/>
|
android:padding="10dp"
|
||||||
|
android:text="设备初始化"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="30sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
|
||||||
</LinearLayout>
|
<Space
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivQrCode"
|
||||||
|
android:layout_width="200dp"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:layout_gravity="center_horizontal|bottom"
|
||||||
|
android:layout_marginBottom="50dp"
|
||||||
|
tools:src="@mipmap/ic_logo1024"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llNetwork"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<!-- Loading 动画容器 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llLoading"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="visible"
|
||||||
|
android:layout_marginTop="260dp">
|
||||||
|
|
||||||
|
<!-- 加载动画 -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivLoading"
|
||||||
|
android:layout_width="160dp"
|
||||||
|
android:layout_height="160dp"
|
||||||
|
android:src="@drawable/loading_spinner"
|
||||||
|
android:contentDescription="加载中" />
|
||||||
|
|
||||||
|
<!-- 倒计时文字 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCountdown"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="60秒"
|
||||||
|
android:textSize="40sp"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginTop="50dp" />
|
||||||
|
|
||||||
|
<!-- 提示文字 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="网络连接检测中,请稍后……"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="#555555"
|
||||||
|
android:layout_marginTop="20dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 连接网络按钮容器 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llNetworkButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<!-- 网络错误图标 -->
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="140dp"
|
||||||
|
android:layout_height="140dp"
|
||||||
|
android:src="@drawable/ic_network_error"
|
||||||
|
android:contentDescription="网络连接失败"
|
||||||
|
android:layout_marginBottom="30dp" />
|
||||||
|
|
||||||
|
<!-- 连接失败提示 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="网络连接失败"
|
||||||
|
android:textSize="36sp"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginBottom="40dp" />
|
||||||
|
|
||||||
|
<!-- 连接网络按钮 -->
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnConnectNetwork"
|
||||||
|
android:layout_width="350dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:text="连接网络"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:background="@drawable/btn_connect_network" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
<item name="colorOnSecondary">@color/black</item>
|
<item name="colorOnSecondary">@color/black</item>
|
||||||
<!-- Status bar color. -->
|
<!-- Status bar color. -->
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
|
<!-- 导航栏颜色与背景一致,避免启动时黑色闪烁;上滑 transient 导航栏由系统控制不受影响 -->
|
||||||
|
<item name="android:navigationBarColor">@color/bg_color</item>
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<!-- <item name="android:layout_width">828dp</item>-->
|
<!-- <item name="android:layout_width">828dp</item>-->
|
||||||
<item name="android:fitsSystemWindows">false</item>
|
<item name="android:fitsSystemWindows">false</item>
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
<item name="colorOnSecondary">@color/black</item>
|
<item name="colorOnSecondary">@color/black</item>
|
||||||
<!-- Status bar color. -->
|
<!-- Status bar color. -->
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
|
<!-- 导航栏颜色与背景一致,避免启动时黑色闪烁;上滑 transient 导航栏由系统控制不受影响 -->
|
||||||
|
<item name="android:navigationBarColor">@color/bg_color</item>
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<!-- <item name="android:layout_width">828dp</item>-->
|
<!-- <item name="android:layout_width">828dp</item>-->
|
||||||
<item name="android:fitsSystemWindows">false</item>
|
<item name="android:fitsSystemWindows">false</item>
|
||||||
@@ -19,6 +21,11 @@
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- 非启动页主题:windowBackground 为纯色,避免 bg_splash 闪烁 -->
|
||||||
|
<style name="Theme.DishMatch.NoSplash" parent="Theme.DishMatch">
|
||||||
|
<item name="android:windowBackground">@color/bg_color</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="CookButtonStyle" parent="Widget.MaterialComponents.Button">
|
<style name="CookButtonStyle" parent="Widget.MaterialComponents.Button">
|
||||||
<!-- 禁用默认背景色 -->
|
<!-- 禁用默认背景色 -->
|
||||||
<item name="backgroundTint">@null</item>
|
<item name="backgroundTint">@null</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user