设备(1)
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
@@ -8,8 +8,12 @@ import com.example.defenseapplication.databinding.ItemDeviceBinding
|
||||
|
||||
data class DeviceUi(
|
||||
val name: String,
|
||||
val status: String,
|
||||
val deviceId: String = ""
|
||||
) {
|
||||
val isOnline: Boolean
|
||||
)
|
||||
get() = status == "1"
|
||||
}
|
||||
|
||||
class DeviceAdapter(
|
||||
private val onItemClick: (DeviceUi) -> Unit = {}
|
||||
@@ -39,12 +43,27 @@ class DeviceAdapter(
|
||||
|
||||
fun bind(item: DeviceUi) {
|
||||
binding.tvDeviceType.text = item.name
|
||||
if (item.isOnline) {
|
||||
binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.green))
|
||||
binding.tvDeviceName.text = "\u25CF 正在运行"
|
||||
} else {
|
||||
binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.red))
|
||||
binding.tvDeviceName.text = "\u25CF 离线"
|
||||
when (item.status) {
|
||||
"1" -> {
|
||||
binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.green))
|
||||
binding.tvDeviceName.text = "\u25CF 在线"
|
||||
}
|
||||
"0" -> {
|
||||
binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.red))
|
||||
binding.tvDeviceName.text = "\u25CF 离线"
|
||||
}
|
||||
"2" -> {
|
||||
binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.orange))
|
||||
binding.tvDeviceName.text = "\u25CF 故障"
|
||||
}
|
||||
"3" -> {
|
||||
binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.gray))
|
||||
binding.tvDeviceName.text = "\u25CF 到期"
|
||||
}
|
||||
else -> {
|
||||
binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.gray))
|
||||
binding.tvDeviceName.text = "\u25CF 未知"
|
||||
}
|
||||
}
|
||||
binding.root.setOnClickListener {
|
||||
onItemClick(item)
|
||||
|
||||
@@ -1,38 +1,18 @@
|
||||
package com.example.defenseapplication.base
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.example.defenseapplication.utils.LanguageUtil
|
||||
import com.example.defenseapplication.utils.ActivityManager
|
||||
|
||||
/**
|
||||
* 支持语言切换的 Activity 基类
|
||||
* 所有需要支持多语言的 Activity 都应该继承此类
|
||||
*/
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
|
||||
override fun attachBaseContext(newBase: Context) {
|
||||
// 在 Activity 创建前应用语言设置
|
||||
val context = LanguageUtil.attachBaseContext(newBase)
|
||||
super.attachBaseContext(context)
|
||||
}
|
||||
open class BaseActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// 确保语言设置被应用
|
||||
LanguageUtil.updateResources(this)
|
||||
ActivityManager.addActivity(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换语言
|
||||
* 调用后会重新创建 Activity 以应用新语言
|
||||
*/
|
||||
protected fun switchLanguage(language: String) {
|
||||
val currentLang = LanguageUtil.getCurrentLanguage(this)
|
||||
if (currentLang != language) {
|
||||
LanguageUtil.switchLanguage(this, language)
|
||||
// 重新创建 Activity 以应用新语言
|
||||
recreate()
|
||||
}
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
ActivityManager.removeActivity(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,26 @@
|
||||
package com.example.defenseapplication.home
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.example.defenseapplication.R
|
||||
import com.example.defenseapplication.adapter.AddDeviceAdapter
|
||||
import com.example.defenseapplication.adapter.Device
|
||||
import com.example.defenseapplication.databinding.AddDeviceActivityBinding
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import com.maning.mlkitscanner.scan.MNScanManager
|
||||
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
|
||||
|
||||
//添加设备页面
|
||||
class AddDeviceActivity : AppCompatActivity() {
|
||||
@@ -20,6 +28,86 @@ class AddDeviceActivity : AppCompatActivity() {
|
||||
private lateinit var binding: AddDeviceActivityBinding
|
||||
private lateinit var adapter: AddDeviceAdapter
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
private val requestPermissionsLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestMultiplePermissions()
|
||||
) { permissions ->
|
||||
val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false
|
||||
|
||||
val storageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false
|
||||
} else {
|
||||
permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false
|
||||
}
|
||||
|
||||
if (cameraGranted && storageGranted) {
|
||||
startScan()
|
||||
} else {
|
||||
Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPermissionsAndScan() {
|
||||
val cameraPermission = ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.CAMERA
|
||||
)
|
||||
|
||||
val storagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
)
|
||||
} else {
|
||||
ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
|
||||
if (cameraPermission == PackageManager.PERMISSION_GRANTED &&
|
||||
storagePermission == PackageManager.PERMISSION_GRANTED) {
|
||||
startScan()
|
||||
} else {
|
||||
val permissionsToRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
arrayOf(
|
||||
Manifest.permission.CAMERA,
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
)
|
||||
} else {
|
||||
arrayOf(
|
||||
Manifest.permission.CAMERA,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
requestPermissionsLauncher.launch(permissionsToRequest)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startScan() {
|
||||
MNScanManager.startScan(this, object: MNScanCallback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
when (resultCode) {
|
||||
MNScanManager.RESULT_SUCCESS -> {
|
||||
val result = data?.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS)
|
||||
if (!result.isNullOrEmpty()) {
|
||||
ToastUtils.showToast(this@AddDeviceActivity, "扫码成功: $result")
|
||||
} else {
|
||||
ToastUtils.showToast(this@AddDeviceActivity, "扫码结果为空")
|
||||
}
|
||||
}
|
||||
MNScanManager.RESULT_FAIL -> {
|
||||
val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
|
||||
ToastUtils.showToast(this@AddDeviceActivity, "扫码失败: $error")
|
||||
}
|
||||
MNScanManager.RESULT_CANCLE -> {
|
||||
ToastUtils.showToast(this@AddDeviceActivity, "扫码取消")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = AddDeviceActivityBinding.inflate(layoutInflater)
|
||||
@@ -32,6 +120,10 @@ class AddDeviceActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
|
||||
binding.btnScanAdd.setOnClickListener {
|
||||
checkPermissionsAndScan()
|
||||
}
|
||||
|
||||
// 开始播放扫描动画,动画结束后再显示设备列表
|
||||
startScanAnimationThenShowList()
|
||||
}
|
||||
|
||||
@@ -6,15 +6,23 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.net.wifi.ScanResult
|
||||
import android.net.wifi.WifiConfiguration
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@@ -29,8 +37,13 @@ class AddFamilyActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: AddFamilyActivityBinding
|
||||
private lateinit var wifiManager: WifiManager
|
||||
private lateinit var connectivityManager: ConnectivityManager
|
||||
private lateinit var wifiScanReceiver: BroadcastReceiver
|
||||
private var popupWindow: PopupWindow? = null
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var isConnecting = false
|
||||
private var targetWifiName: String = ""
|
||||
private var networkCallback: ConnectivityManager.NetworkCallback? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -58,6 +71,7 @@ class AddFamilyActivity : AppCompatActivity() {
|
||||
}
|
||||
})
|
||||
wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
wifiScanReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
@@ -68,11 +82,161 @@ class AddFamilyActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
binding.btnConfirm.setOnClickListener {
|
||||
val intent=Intent(this, ConnectDeviceActivity::class.java)
|
||||
startActivity( intent)
|
||||
//startActivity(Intent(this, ConnectDeviceActivity::class.java))
|
||||
if (isConnecting) {
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
val wifiName = binding.etWifiName.text.toString().trim()
|
||||
val wifiPassword = binding.etWifiPassword.text.toString()
|
||||
|
||||
if (wifiName.isEmpty()) {
|
||||
Toast.makeText(this, R.string.enter_wifi_name, Toast.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (wifiPassword.isEmpty()) {
|
||||
Toast.makeText(this, R.string.enter_wifi_password, Toast.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
isConnecting = true
|
||||
binding.btnConfirm.isEnabled = false
|
||||
|
||||
verifyWifiPassword(wifiName, wifiPassword)
|
||||
}
|
||||
}
|
||||
|
||||
private fun verifyWifiPassword(wifiName: String, wifiPassword: String) {
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
!= PackageManager.PERMISSION_GRANTED ||
|
||||
ActivityCompat.checkSelfPermission(this, Manifest.permission.CHANGE_WIFI_STATE)
|
||||
!= PackageManager.PERMISSION_GRANTED ||
|
||||
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.CHANGE_WIFI_STATE,
|
||||
Manifest.permission.ACCESS_NETWORK_STATE),
|
||||
1002)
|
||||
return
|
||||
}
|
||||
|
||||
targetWifiName = wifiName
|
||||
|
||||
if (!wifiManager.isWifiEnabled) {
|
||||
wifiManager.isWifiEnabled = true
|
||||
}
|
||||
|
||||
val existingConfig = findExistingWifiConfig(wifiName)
|
||||
var netId: Int
|
||||
|
||||
if (existingConfig != null) {
|
||||
netId = existingConfig.networkId
|
||||
existingConfig.preSharedKey = "\"$wifiPassword\""
|
||||
wifiManager.updateNetwork(existingConfig)
|
||||
} else {
|
||||
val wifiConfig = createWifiConfig(wifiName, wifiPassword)
|
||||
netId = wifiManager.addNetwork(wifiConfig)
|
||||
}
|
||||
|
||||
if (netId == -1) {
|
||||
isConnecting = false
|
||||
binding.btnConfirm.isEnabled = true
|
||||
ToastUtils.showError(this, getString(R.string.wifi_connection_failed))
|
||||
return
|
||||
}
|
||||
|
||||
networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
super.onAvailable(network)
|
||||
checkWifiConnected()
|
||||
}
|
||||
|
||||
override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
|
||||
super.onCapabilitiesChanged(network, capabilities)
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||
checkWifiConnected()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val request = NetworkRequest.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.build()
|
||||
|
||||
connectivityManager.registerNetworkCallback(request, networkCallback!!)
|
||||
|
||||
wifiManager.enableNetwork(netId, true)
|
||||
wifiManager.saveConfiguration()
|
||||
|
||||
handler.postDelayed({
|
||||
if (isConnecting) {
|
||||
isConnecting = false
|
||||
binding.btnConfirm.isEnabled = true
|
||||
networkCallback?.let {
|
||||
try {
|
||||
connectivityManager.unregisterNetworkCallback(it)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
networkCallback = null
|
||||
ToastUtils.showError(this, getString(R.string.wifi_connection_failed))
|
||||
}
|
||||
}, 15000)
|
||||
}
|
||||
|
||||
private fun findExistingWifiConfig(wifiName: String): WifiConfiguration? {
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
return null
|
||||
}
|
||||
val configuredNetworks = wifiManager.configuredNetworks
|
||||
configuredNetworks?.forEach { config ->
|
||||
if (config.SSID == "\"$wifiName\"") {
|
||||
return config
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun checkWifiConnected() {
|
||||
if (!isConnecting) return
|
||||
|
||||
val info = wifiManager.connectionInfo
|
||||
if (info.ssid == "\"$targetWifiName\"" && info.networkId != -1) {
|
||||
isConnecting = false
|
||||
binding.btnConfirm.isEnabled = true
|
||||
networkCallback?.let {
|
||||
try {
|
||||
connectivityManager.unregisterNetworkCallback(it)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
networkCallback = null
|
||||
runOnUiThread {
|
||||
ToastUtils.showSuccess(this@AddFamilyActivity, getString(R.string.wifi_connection_success))
|
||||
val intent = Intent(this@AddFamilyActivity, ConnectDeviceActivity::class.java)
|
||||
intent.putExtra("wifi_name", targetWifiName)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWifiConfig(ssid: String, password: String): WifiConfiguration {
|
||||
val config = WifiConfiguration()
|
||||
config.SSID = "\"$ssid\""
|
||||
config.preSharedKey = "\"$password\""
|
||||
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)
|
||||
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN)
|
||||
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA)
|
||||
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP)
|
||||
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP)
|
||||
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP)
|
||||
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP)
|
||||
return config
|
||||
}
|
||||
|
||||
private fun showWifiListDialog() {
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
!= PackageManager.PERMISSION_GRANTED ||
|
||||
@@ -151,5 +315,34 @@ class AddFamilyActivity : AppCompatActivity() {
|
||||
super.onStop()
|
||||
unregisterReceiver(wifiScanReceiver)
|
||||
popupWindow?.dismiss()
|
||||
networkCallback?.let {
|
||||
try {
|
||||
connectivityManager.unregisterNetworkCallback(it)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
networkCallback = null
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
when (requestCode) {
|
||||
1002 -> {
|
||||
if (grantResults.isNotEmpty() &&
|
||||
grantResults.size >= 3 &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED &&
|
||||
grantResults[1] == PackageManager.PERMISSION_GRANTED &&
|
||||
grantResults[2] == PackageManager.PERMISSION_GRANTED) {
|
||||
val wifiName = binding.etWifiName.text.toString().trim()
|
||||
val wifiPassword = binding.etWifiPassword.text.toString()
|
||||
verifyWifiPassword(wifiName, wifiPassword)
|
||||
} else {
|
||||
isConnecting = false
|
||||
binding.btnConfirm.isEnabled = true
|
||||
Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import com.example.defenseapplication.bean.DeviceBean
|
||||
import com.example.defenseapplication.bean.FamilyBean
|
||||
import com.example.defenseapplication.bean.SwitchFamilyRequest
|
||||
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
|
||||
import com.example.defenseapplication.utils.DeviceIdEvent
|
||||
import com.example.defenseapplication.utils.FamilySwitchEvent
|
||||
import com.example.defenseapplication.utils.MessageStatusManager
|
||||
import com.example.defenseapplication.utils.RetrofitNetwork
|
||||
@@ -52,6 +53,10 @@ class HomeMenuFragment : Fragment() {
|
||||
|
||||
private var isFamilyExpanded = false
|
||||
private lateinit var currentFamily: String
|
||||
private var currentPage = 1
|
||||
private val pageSize = 10
|
||||
private var hasMore = true
|
||||
private var isLoading = false
|
||||
|
||||
private val requestPermissionsLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestMultiplePermissions()
|
||||
@@ -222,6 +227,23 @@ class HomeMenuFragment : Fragment() {
|
||||
)
|
||||
}
|
||||
|
||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||
refreshDeviceList()
|
||||
}
|
||||
|
||||
binding.rvDeviceList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
val layoutManager = recyclerView.layoutManager as GridLayoutManager
|
||||
val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
|
||||
val totalItemCount = layoutManager.itemCount
|
||||
|
||||
if (!isLoading && hasMore && lastVisibleItemPosition >= totalItemCount - 1 && dy > 0) {
|
||||
loadMoreDevices()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
binding.familyHeaderLayout.setOnClickListener {
|
||||
toggleFamilyList()
|
||||
}
|
||||
@@ -349,8 +371,10 @@ class HomeMenuFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchDeviceList() {
|
||||
if (!canViewDevice) return
|
||||
private fun fetchDeviceList(page: Int = 1, isLoadMore: Boolean = false) {
|
||||
if (!canViewDevice || isLoading) return
|
||||
|
||||
isLoading = true
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
@@ -358,21 +382,49 @@ class HomeMenuFragment : Fragment() {
|
||||
withContext(Dispatchers.Main) {
|
||||
Log.d("DeviceList", "code = ${response.code}, data = ${response.data}")
|
||||
if (response.code == 200 && response.data != null) {
|
||||
deviceBeanList = response.data
|
||||
val newDevices = response.data
|
||||
if (isLoadMore) {
|
||||
deviceBeanList = deviceBeanList + newDevices
|
||||
hasMore = newDevices.size >= pageSize
|
||||
} else {
|
||||
deviceBeanList = newDevices
|
||||
hasMore = newDevices.size >= pageSize
|
||||
}
|
||||
Log.d("DeviceList", "deviceBeanList size = ${deviceBeanList.size}")
|
||||
updateDeviceList()
|
||||
} else {
|
||||
Toast.makeText(requireContext(), response.msg, Toast.LENGTH_SHORT).show()
|
||||
if (isLoadMore) {
|
||||
hasMore = false
|
||||
}
|
||||
}
|
||||
isLoading = false
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
isLoading = false
|
||||
if (isLoadMore) {
|
||||
hasMore = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshDeviceList() {
|
||||
currentPage = 1
|
||||
hasMore = true
|
||||
fetchDeviceList(currentPage, false)
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
|
||||
private fun loadMoreDevices() {
|
||||
if (isLoading || !hasMore) return
|
||||
currentPage++
|
||||
fetchDeviceList(currentPage, true)
|
||||
}
|
||||
|
||||
private fun toggleFamilyList() {
|
||||
isFamilyExpanded = !isFamilyExpanded
|
||||
val visibility = if (isFamilyExpanded) View.VISIBLE else View.GONE
|
||||
@@ -396,12 +448,12 @@ class HomeMenuFragment : Fragment() {
|
||||
|
||||
private fun updateDeviceList() {
|
||||
val deviceUiList = deviceBeanList.map {
|
||||
DeviceUi(it.deviceName, it.status == "0")
|
||||
DeviceUi(it.deviceName, it.status, it.id)
|
||||
}
|
||||
|
||||
if (deviceUiList.isEmpty()) {
|
||||
deviceAdapter.submitList(listOf(
|
||||
DeviceUi(getString(R.string.no_device), false)
|
||||
DeviceUi(getString(R.string.no_device), "0")
|
||||
))
|
||||
} else {
|
||||
deviceAdapter.submitList(deviceUiList)
|
||||
@@ -409,10 +461,16 @@ class HomeMenuFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun onDeviceClicked(device: DeviceUi) {
|
||||
if (device.isOnline) return
|
||||
showDefenseDialog(
|
||||
config = DefenseDialogs.deviceOfflineConfig(requireContext())
|
||||
)
|
||||
if (device.isOnline) {
|
||||
DeviceIdEvent.setDeviceId(device.deviceId)
|
||||
val intent = Intent(requireContext(), com.example.defenseapplication.liveVideo.LiveVideoActivity::class.java)
|
||||
intent.putExtra("device_name", device.name)
|
||||
startActivity(intent)
|
||||
} else {
|
||||
showDefenseDialog(
|
||||
config = DefenseDialogs.deviceOfflineConfig(requireContext())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dpToPx(dp: Int): Int {
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package com.example.defenseapplication.liveVideo
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.example.defenseapplication.R
|
||||
import com.example.defenseapplication.databinding.AlarmLogActivityBinding
|
||||
import com.example.defenseapplication.databinding.DeviceInfoActivityBinding
|
||||
import com.example.defenseapplication.utils.DeviceIdEvent
|
||||
import com.example.defenseapplication.utils.RetrofitNetwork
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
//设备信息
|
||||
class DeviceInfoActivity : AppCompatActivity() {
|
||||
private lateinit var binding: DeviceInfoActivityBinding
|
||||
@@ -23,5 +26,38 @@ class DeviceInfoActivity : AppCompatActivity() {
|
||||
binding.ivBack.setOnClickListener {
|
||||
finish()
|
||||
}
|
||||
fetchDeviceInfo()
|
||||
}
|
||||
|
||||
private fun fetchDeviceInfo() {
|
||||
val deviceId = DeviceIdEvent.getDeviceId()
|
||||
if (deviceId.isNullOrEmpty()) {
|
||||
Toast.makeText(this, "设备ID为空", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService().getDeviceInfo(deviceId)
|
||||
withContext(Dispatchers.Main) {
|
||||
if (response.code == 200 && response.data != null) {
|
||||
updateDeviceInfo(response.data)
|
||||
} else {
|
||||
Toast.makeText(this@DeviceInfoActivity, response.msg, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(this@DeviceInfoActivity, "网络请求失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDeviceInfo(device: com.example.defenseapplication.bean.DeviceBean) {
|
||||
binding.tvDeviceModelValue.text = device.deviceNo.toString() ?: "未知型号"
|
||||
binding.tvDeviceNoValue.text = device.startTime.toString() ?: "自动布防开始时间"
|
||||
binding.tvFwVersionValue.text = device.endTime.toString() ?: "自动布防结束时间"
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,12 @@ import android.view.animation.ScaleAnimation
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedDispatcher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.ui.test.isEnabled
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.example.defenseapplication.R
|
||||
import com.example.defenseapplication.base.BaseActivity
|
||||
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
|
||||
import com.example.defenseapplication.utils.ActivityManager
|
||||
import com.example.defenseapplication.utils.DeviceIdEvent
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import com.gyf.immersionbar.ktx.destroyImmersionBar
|
||||
import java.io.File
|
||||
@@ -33,7 +34,7 @@ import java.io.IOException
|
||||
|
||||
private const val TAG = "LiveVideoActivity"
|
||||
//智能防御机A1
|
||||
class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
|
||||
private lateinit var binding: LiveVideoActivityBinding
|
||||
|
||||
private var mediaPlayer: MediaPlayer? = null
|
||||
@@ -72,6 +73,11 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
.titleBar(binding.topBar)
|
||||
.init()
|
||||
|
||||
val deviceName = intent.getStringExtra("device_name")
|
||||
if (!deviceName.isNullOrEmpty()) {
|
||||
binding.tvTitle.text = deviceName
|
||||
}
|
||||
|
||||
initSurfaceView()
|
||||
initListener()
|
||||
}
|
||||
@@ -163,6 +169,10 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
|
||||
private fun initListener() {
|
||||
binding.btnBack.setOnClickListener {
|
||||
ActivityManager.finishExceptHome()
|
||||
val intent = Intent(this, com.example.defenseapplication.home.HomeActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.example.defenseapplication.utils
|
||||
|
||||
import android.app.Activity
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.Stack
|
||||
|
||||
object ActivityManager {
|
||||
private val activityStack = Stack<WeakReference<Activity>>()
|
||||
|
||||
fun addActivity(activity: Activity) {
|
||||
activityStack.push(WeakReference(activity))
|
||||
}
|
||||
|
||||
fun removeActivity(activity: Activity) {
|
||||
activityStack.removeIf { it.get() == activity }
|
||||
}
|
||||
|
||||
fun finishActivity(activity: Activity) {
|
||||
activity.finish()
|
||||
removeActivity(activity)
|
||||
}
|
||||
|
||||
fun finishAllActivities() {
|
||||
while (activityStack.isNotEmpty()) {
|
||||
val activityRef = activityStack.pop()
|
||||
activityRef.get()?.finish()
|
||||
}
|
||||
activityStack.clear()
|
||||
}
|
||||
|
||||
fun finishToActivity(cls: Class<*>) {
|
||||
val tempStack = Stack<WeakReference<Activity>>()
|
||||
|
||||
while (activityStack.isNotEmpty()) {
|
||||
val activityRef = activityStack.pop()
|
||||
val activity = activityRef.get()
|
||||
|
||||
if (activity != null && activity.javaClass == cls) {
|
||||
tempStack.push(activityRef)
|
||||
break
|
||||
} else if (activity != null) {
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
while (tempStack.isNotEmpty()) {
|
||||
activityStack.push(tempStack.pop())
|
||||
}
|
||||
}
|
||||
|
||||
fun finishExceptHome() {
|
||||
val tempStack = Stack<WeakReference<Activity>>()
|
||||
var foundHome = false
|
||||
|
||||
while (activityStack.isNotEmpty()) {
|
||||
val activityRef = activityStack.pop()
|
||||
val activity = activityRef.get()
|
||||
|
||||
if (activity != null) {
|
||||
val className = activity.javaClass.simpleName
|
||||
if (className == "HomeActivity" || className == "MainActivity") {
|
||||
tempStack.push(activityRef)
|
||||
foundHome = true
|
||||
break
|
||||
} else {
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundHome) {
|
||||
while (tempStack.isNotEmpty()) {
|
||||
activityStack.push(tempStack.pop())
|
||||
}
|
||||
} else {
|
||||
while (tempStack.isNotEmpty()) {
|
||||
activityStack.push(tempStack.pop())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentActivity(): Activity? {
|
||||
if (activityStack.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
return activityStack.peek().get()
|
||||
}
|
||||
|
||||
fun getActivityCount(): Int {
|
||||
return activityStack.size
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,19 @@ interface ApiService {
|
||||
@GET("/app/appMessage/list")
|
||||
suspend fun getMessage(): GetCodeBean<List<MessageGroup>>
|
||||
|
||||
/**
|
||||
* 获取设备信息
|
||||
*/
|
||||
@PUT("/app/updateDeviceInfo")
|
||||
suspend fun updateDeviceInfo(@Body deviceBean: DeviceBean): GetCodeBean<DeviceBean>
|
||||
|
||||
|
||||
/**
|
||||
* 获取设备信息
|
||||
*/
|
||||
@GET("/app/deviceInfo/{id}")
|
||||
suspend fun getDeviceInfo(@retrofit2.http.Path("id") id: String): GetCodeBean<DeviceBean>
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example.defenseapplication.utils
|
||||
|
||||
object DeviceIdEvent {
|
||||
private val listeners = mutableListOf<DeviceIdListener>()
|
||||
private var currentDeviceId: String? = null
|
||||
|
||||
interface DeviceIdListener {
|
||||
fun onDeviceIdChanged(deviceId: String)
|
||||
}
|
||||
|
||||
fun addListener(listener: DeviceIdListener) {
|
||||
if (!listeners.contains(listener)) {
|
||||
listeners.add(listener)
|
||||
currentDeviceId?.let { listener.onDeviceIdChanged(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun removeListener(listener: DeviceIdListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
fun setDeviceId(deviceId: String) {
|
||||
currentDeviceId = deviceId
|
||||
listeners.forEach { it.onDeviceIdChanged(deviceId) }
|
||||
}
|
||||
|
||||
fun getDeviceId(): String? {
|
||||
return currentDeviceId
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@
|
||||
android:textSize="14dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDeviceModelValue"
|
||||
android:text="VDF-2000-A1"
|
||||
android:textColor="@color/gray"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -59,11 +60,12 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/auto_arms_start_time"
|
||||
android:text="@string/device_no"
|
||||
android:textSize="14dp"/>
|
||||
|
||||
<TextView
|
||||
android:text="VDF20260318001759"
|
||||
android:id="@+id/tvDeviceNoValue"
|
||||
android:text=""
|
||||
android:textColor="@color/gray"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -77,11 +79,12 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/auto_arms_end_time"
|
||||
android:text="@string/fw_version"
|
||||
android:textSize="14dp"/>
|
||||
|
||||
<TextView
|
||||
android:text="20261015-build1008"
|
||||
android:id="@+id/tvFwVersionValue"
|
||||
android:text=""
|
||||
android:textColor="@color/gray"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -142,18 +142,24 @@
|
||||
android:rowCount="1" >
|
||||
</GridLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvDeviceList"
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_weight="1"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:paddingBottom="16dp"
|
||||
tools:listitem="@layout/item_device" />
|
||||
android:layout_weight="1">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvDeviceList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:paddingBottom="16dp"
|
||||
tools:listitem="@layout/item_device" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutNoPermission"
|
||||
|
||||
@@ -425,4 +425,6 @@
|
||||
<string name="invite_friend">快来加入我!扫码下载APP</string>
|
||||
<string name="share_to">分享至</string>
|
||||
<string name="no_share_app">暂无可用分享应用</string>
|
||||
<string name="device_no">设备编号</string>
|
||||
<string name="fw_version">固件版本</string>
|
||||
</resources>
|
||||
@@ -19,5 +19,6 @@
|
||||
<color name="ic_blake">#111111</color>
|
||||
<color name="green_light">#E8F7F7</color>
|
||||
<color name="gray_divider">#E5E5E5</color>
|
||||
<color name="orange">#FF9800</color>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -188,6 +188,8 @@
|
||||
<string name="enter_warning_voice_content_system_will_generate_voice_automatically">Enter warning voice content, system will generate voice automatically.</string>
|
||||
<string name="device_info">Device info</string>
|
||||
<string name="device_model">Device model</string>
|
||||
<string name="device_no">Device No</string>
|
||||
<string name="fw_version">FW Version</string>
|
||||
<string name="auto_arms_start_time">Auto arm start time</string>
|
||||
<string name="auto_arms_end_time">Auto arm End time</string>
|
||||
<string name="please_select_at_least_one_user">Please select at least one user</string>
|
||||
|
||||
Reference in New Issue
Block a user