refactor: improve layout and formatting of HistoryScreen UI components

This commit is contained in:
Nedifinita
2025-07-19 17:34:02 +08:00
parent 4f2c1f0e24
commit 560797b679
5 changed files with 285 additions and 124 deletions

View File

@@ -19,8 +19,6 @@ import java.util.*
class BLEClient(private val context: Context) : BluetoothGattCallback() { class BLEClient(private val context: Context) : BluetoothGattCallback() {
companion object { companion object {
const val TAG = "LBJ_BT" const val TAG = "LBJ_BT"
const val SCAN_PERIOD = 10000L
val SERVICE_UUID = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb") val SERVICE_UUID = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb")
val CHAR_UUID = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb") val CHAR_UUID = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb")
@@ -42,20 +40,69 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
private var targetDeviceName: String? = null private var targetDeviceName: String? = null
private var bluetoothLeScanner: BluetoothLeScanner? = null private var bluetoothLeScanner: BluetoothLeScanner? = null
private var continuousScanning = false
private var autoReconnect = true
private var lastKnownDeviceAddress: String? = null
private var connectionAttempts = 0
private var isReconnecting = false
private val leScanCallback = object : ScanCallback() { private val leScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) { override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device val device = result.device
val deviceName = device.name val deviceName = device.name
if (targetDeviceName != null) {
if (deviceName == null || !deviceName.equals(targetDeviceName, ignoreCase = true)) { val shouldShowDevice = when {
return targetDeviceName != null -> {
deviceName != null && deviceName.equals(targetDeviceName, ignoreCase = true)
}
else -> {
deviceName != null && (
deviceName.contains("LBJ", ignoreCase = true) ||
deviceName.contains("Receiver", ignoreCase = true) ||
deviceName.contains("Train", ignoreCase = true) ||
deviceName.contains("Console", ignoreCase = true) ||
deviceName.contains("ESP", ignoreCase = true) ||
deviceName.contains("Arduino", ignoreCase = true) ||
deviceName.contains("BLE", ignoreCase = true) ||
deviceName.contains("UART", ignoreCase = true) ||
deviceName.contains("Serial", ignoreCase = true)
) && !(
deviceName.contains("Midea", ignoreCase = true) ||
deviceName.contains("TV", ignoreCase = true) ||
deviceName.contains("Phone", ignoreCase = true) ||
deviceName.contains("Watch", ignoreCase = true) ||
deviceName.contains("Headset", ignoreCase = true) ||
deviceName.contains("Speaker", ignoreCase = true)
)
} }
} }
scanCallback?.invoke(device)
if (shouldShowDevice) {
Log.d(TAG, "Showing filtered device: $deviceName")
scanCallback?.invoke(device)
}
if (targetDeviceName != null && !isConnected && !isReconnecting) {
if (deviceName != null && deviceName.equals(targetDeviceName, ignoreCase = true)) {
Log.i(TAG, "Found target device: $deviceName, auto-connecting")
lastKnownDeviceAddress = device.address
connectImmediately(device.address)
}
}
if (lastKnownDeviceAddress == device.address && !isConnected && !isReconnecting) {
Log.i(TAG, "Found known device, reconnecting immediately")
connectImmediately(device.address)
}
} }
override fun onScanFailed(errorCode: Int) { override fun onScanFailed(errorCode: Int) {
Log.e(TAG, "BLE scan failed code=$errorCode") Log.e(TAG, "BLE scan failed code=$errorCode")
if (continuousScanning) {
handler.post {
restartScan()
}
}
} }
} }
@@ -107,12 +154,9 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
return return
} }
handler.postDelayed({
stopScan()
}, SCAN_PERIOD)
isScanning = true isScanning = true
Log.d(TAG, "Starting BLE scan target=${targetDeviceName ?: "Any"}") continuousScanning = true
Log.d(TAG, "Starting continuous BLE scan target=${targetDeviceName ?: "Any"}")
bluetoothLeScanner?.startScan(leScanCallback) bluetoothLeScanner?.startScan(leScanCallback)
} catch (e: SecurityException) { } catch (e: SecurityException) {
Log.e(TAG, "Scan security error: ${e.message}") Log.e(TAG, "Scan security error: ${e.message}")
@@ -127,6 +171,40 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
if (isScanning) { if (isScanning) {
bluetoothLeScanner?.stopScan(leScanCallback) bluetoothLeScanner?.stopScan(leScanCallback)
isScanning = false isScanning = false
continuousScanning = false
Log.d(TAG, "Stopped BLE scan")
}
}
@SuppressLint("MissingPermission")
private fun restartScan() {
if (!continuousScanning) return
try {
bluetoothLeScanner?.stopScan(leScanCallback)
bluetoothLeScanner?.startScan(leScanCallback)
isScanning = true
Log.d(TAG, "Restarted BLE scan")
} catch (e: Exception) {
Log.e(TAG, "Failed to restart scan: ${e.message}")
}
}
private fun connectImmediately(address: String) {
if (isReconnecting) return
isReconnecting = true
handler.post {
connect(address) { connected ->
isReconnecting = false
if (connected) {
connectionAttempts = 0
Log.i(TAG, "Successfully connected to $address")
} else {
connectionAttempts++
Log.w(TAG, "Connection attempt $connectionAttempts failed for $address")
}
}
} }
} }
@@ -185,16 +263,6 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
Log.d(TAG, "Connecting to address=$address") Log.d(TAG, "Connecting to address=$address")
handler.postDelayed({
if (!isConnected && deviceAddress == address) {
Log.e(TAG, "Connection timeout reconnecting")
bluetoothGatt?.close()
bluetoothGatt =
device.connectGatt(context, false, this, BluetoothDevice.TRANSPORT_LE)
}
}, 10000)
return true return true
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Connection failed: ${e.message}") Log.e(TAG, "Connection failed: ${e.message}")
@@ -286,30 +354,30 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
if (status != BluetoothGatt.GATT_SUCCESS) { if (status != BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "Connection error status=$status") Log.e(TAG, "Connection error status=$status")
isConnected = false isConnected = false
isReconnecting = false
if (status == 133 || status == 8) { if (status == 133 || status == 8) {
Log.e(TAG, "GATT error closing connection") Log.e(TAG, "GATT error, attempting immediate reconnection")
try { try {
gatt.close() gatt.close()
bluetoothGatt = null bluetoothGatt = null
deviceAddress?.let { address -> deviceAddress?.let { address ->
handler.postDelayed({ if (autoReconnect) {
Log.d(TAG, "Reconnecting to device") Log.d(TAG, "Immediate reconnection to device")
val device = handler.post {
BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address) val device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address)
bluetoothGatt = device.connectGatt( bluetoothGatt = device.connectGatt(
context, context,
false, false,
this, this,
BluetoothDevice.TRANSPORT_LE BluetoothDevice.TRANSPORT_LE
) )
}, 2000) }
}
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Reconnect error: ${e.message}") Log.e(TAG, "Immediate reconnect error: ${e.message}")
} }
} }
@@ -320,32 +388,34 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
when (newState) { when (newState) {
BluetoothProfile.STATE_CONNECTED -> { BluetoothProfile.STATE_CONNECTED -> {
isConnected = true isConnected = true
isReconnecting = false
connectionAttempts = 0
Log.i(TAG, "Connected to GATT server") Log.i(TAG, "Connected to GATT server")
handler.post { connectionStateCallback?.invoke(true) } handler.post { connectionStateCallback?.invoke(true) }
handler.post {
handler.postDelayed({
try { try {
gatt.discoverServices() gatt.discoverServices()
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Service discovery failed: ${e.message}") Log.e(TAG, "Service discovery failed: ${e.message}")
} }
}, 500) }
} }
BluetoothProfile.STATE_DISCONNECTED -> { BluetoothProfile.STATE_DISCONNECTED -> {
isConnected = false isConnected = false
isReconnecting = false
Log.i(TAG, "Disconnected from GATT server") Log.i(TAG, "Disconnected from GATT server")
handler.post { connectionStateCallback?.invoke(false) } handler.post { connectionStateCallback?.invoke(false) }
if (!deviceAddress.isNullOrBlank()) { if (!deviceAddress.isNullOrBlank() && autoReconnect) {
handler.postDelayed({ handler.post {
Log.d(TAG, "Reconnecting after disconnect") Log.d(TAG, "Immediate reconnection after disconnect")
connect(deviceAddress!!, connectionStateCallback) connect(deviceAddress!!, connectionStateCallback)
}, 3000) }
} }
} }
} }
@@ -357,12 +427,14 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
private var lastDataTime = 0L private var lastDataTime = 0L
@Suppress("DEPRECATION")
override fun onCharacteristicChanged( override fun onCharacteristicChanged(
gatt: BluetoothGatt, gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic characteristic: BluetoothGattCharacteristic
) { ) {
super.onCharacteristicChanged(gatt, characteristic) super.onCharacteristicChanged(gatt, characteristic)
@Suppress("DEPRECATION")
val newData = characteristic.value?.let { val newData = characteristic.value?.let {
String(it, StandardCharsets.UTF_8) String(it, StandardCharsets.UTF_8)
} ?: return } ?: return
@@ -381,18 +453,17 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
val bufferContent = dataBuffer.toString() val bufferContent = dataBuffer.toString()
val currentTime = System.currentTimeMillis() val currentTime = System.currentTimeMillis()
if (lastDataTime > 0) {
if (lastDataTime > 0 && currentTime - lastDataTime > 5000) { val timeDiff = currentTime - lastDataTime
Log.w(TAG, "Data timeout ${(currentTime - lastDataTime) / 1000}s") if (timeDiff > 10000) {
Log.w(TAG, "Long data gap: ${timeDiff / 1000}s")
}
} }
Log.d(TAG, "Buffer size=${dataBuffer.length} bytes") Log.d(TAG, "Buffer size=${dataBuffer.length} bytes")
tryExtractJson(bufferContent) tryExtractJson(bufferContent)
lastDataTime = currentTime lastDataTime = currentTime
} }
@@ -511,9 +582,16 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
) )
if (descriptor != null) { if (descriptor != null) {
descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val writeResult = gatt.writeDescriptor(descriptor) val writeResult = gatt.writeDescriptor(descriptor, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
Log.d(TAG, "Descriptor write result=$writeResult") Log.d(TAG, "Descriptor write result=$writeResult")
} else {
@Suppress("DEPRECATION")
descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
@Suppress("DEPRECATION")
val writeResult = gatt.writeDescriptor(descriptor)
Log.d(TAG, "Descriptor write result=$writeResult")
}
} else { } else {
Log.e(TAG, "Descriptor not found") Log.e(TAG, "Descriptor not found")
@@ -540,10 +618,19 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
private fun requestDataAfterDelay() { private fun requestDataAfterDelay() {
handler.postDelayed({ handler.post {
statusCallback?.let { callback -> statusCallback?.let { callback ->
getStatus(callback) getStatus(callback)
} }
}, 1000) }
} }
fun setAutoReconnect(enabled: Boolean) {
autoReconnect = enabled
Log.d(TAG, "Auto reconnect set to: $enabled")
}
fun getConnectionAttempts(): Int = connectionAttempts
fun getLastKnownDeviceAddress(): String? = lastKnownDeviceAddress
} }

View File

@@ -6,6 +6,7 @@ import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import java.io.File import java.io.File
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@@ -30,6 +31,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -109,9 +111,8 @@ class MainActivity : ComponentActivity() {
val locationPermissionsGranted = permissions.filter { it.key.contains("LOCATION") }.all { it.value } val locationPermissionsGranted = permissions.filter { it.key.contains("LOCATION") }.all { it.value }
if (bluetoothPermissionsGranted && locationPermissionsGranted) { if (bluetoothPermissionsGranted && locationPermissionsGranted) {
Log.d(TAG, "Permissions granted") Log.d(TAG, "Permissions granted, starting auto scan and connect")
startAutoScanAndConnect()
startScan()
} else { } else {
Log.e(TAG, "Missing permissions: $permissions") Log.e(TAG, "Missing permissions: $permissions")
deviceStatus = "需要蓝牙和位置权限" deviceStatus = "需要蓝牙和位置权限"
@@ -374,16 +375,16 @@ class MainActivity : ComponentActivity() {
runOnUiThread { runOnUiThread {
if (connected) { if (connected) {
deviceStatus = "已连接" deviceStatus = "已连接"
temporaryStatusMessage = null
Log.d(TAG, "Connected to device name=${device.name ?: "Unknown"}") Log.d(TAG, "Connected to device name=${device.name ?: "Unknown"}")
} else { } else {
deviceStatus = "连接失败或已断开连接" deviceStatus = "连接失败,正在重试..."
Log.e(TAG, "Connection failed name=${device.name ?: "Unknown"}") Log.e(TAG, "Connection failed, auto-retry enabled for name=${device.name ?: "Unknown"}")
} }
} }
} }
deviceAddress = device.address deviceAddress = device.address
stopScan()
} }
@@ -394,6 +395,7 @@ class MainActivity : ComponentActivity() {
try { try {
val isTestData = jsonData.optBoolean("test_flag", false) val isTestData = jsonData.optBoolean("test_flag", false)
lastUpdateTime = Date() lastUpdateTime = Date()
temporaryStatusMessage = null
if (isTestData) { if (isTestData) {
Log.i(TAG, "Received keep-alive signal") Log.i(TAG, "Received keep-alive signal")
@@ -438,14 +440,55 @@ class MainActivity : ComponentActivity() {
private fun updateTemporaryStatusMessage(message: String) { private fun updateTemporaryStatusMessage(message: String) {
temporaryStatusMessage = message temporaryStatusMessage = message
Handler(Looper.getMainLooper()).postDelayed({
if (temporaryStatusMessage == message) {
temporaryStatusMessage = null
}
}, 3000)
} }
private fun startAutoScanAndConnect() {
Log.d(TAG, "Starting auto scan and connect")
if (!hasBluetoothPermissions()) {
Log.e(TAG, "Missing bluetooth permissions for auto scan")
deviceStatus = "需要蓝牙和位置权限"
return
}
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter
if (bluetoothAdapter == null) {
Log.e(TAG, "Bluetooth adapter unavailable")
deviceStatus = "设备不支持蓝牙"
return
}
if (!bluetoothAdapter.isEnabled) {
Log.e(TAG, "Bluetooth adapter disabled")
deviceStatus = "请启用蓝牙"
return
}
bleClient.setAutoReconnect(true)
val targetDeviceName = if (settingsDeviceName.isNotBlank() && settingsDeviceName != "LBJReceiver") {
settingsDeviceName
} else {
"LBJReceiver"
}
Log.d(TAG, "Auto scanning for target device: $targetDeviceName")
deviceStatus = "正在自动扫描连接..."
bleClient.scanDevices(targetDeviceName) { device ->
val deviceName = device.name ?: "Unknown"
Log.d(TAG, "Auto scan found device: $deviceName")
if (deviceName.equals(targetDeviceName, ignoreCase = true)) {
Log.d(TAG, "Found target device, auto connecting to: $deviceName")
bleClient.stopScan()
connectToDevice(device)
}
}
}
private fun startScan() { private fun startScan() {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter val bluetoothAdapter = bluetoothManager.adapter
@@ -461,25 +504,21 @@ class MainActivity : ComponentActivity() {
return return
} }
bleClient.setAutoReconnect(true)
isScanning = true isScanning = true
foundDevices = emptyList() foundDevices = emptyList()
val targetDeviceName = settingsDeviceName.ifBlank { null } val targetDeviceName = if (settingsDeviceName.isNotBlank() && settingsDeviceName != "LBJReceiver") {
Log.d(TAG, "Starting BLE scan target=${targetDeviceName ?: "Any"}") settingsDeviceName
} else {
null
}
Log.d(TAG, "Starting continuous BLE scan target=${targetDeviceName ?: "Any"} (settings=${settingsDeviceName})")
bleClient.scanDevices(targetDeviceName) { device -> bleClient.scanDevices(targetDeviceName) { device ->
if (!foundDevices.any { it.address == device.address }) { if (!foundDevices.any { it.address == device.address }) {
Log.d(TAG, "Found device name=${device.name ?: "Unknown"} address=${device.address}") Log.d(TAG, "Found device name=${device.name ?: "Unknown"} address=${device.address}")
foundDevices = foundDevices + device foundDevices = foundDevices + device
if (targetDeviceName != null && device.name == targetDeviceName) {
Log.d(TAG, "Found target=$targetDeviceName, connecting")
stopScan()
connectToDevice(device)
} else {
if (targetDeviceName == null) {
showConnectionDialog = true
}
}
} }
} }
} }
@@ -491,6 +530,21 @@ class MainActivity : ComponentActivity() {
Log.d(TAG, "Stopped BLE scan") Log.d(TAG, "Stopped BLE scan")
} }
private fun hasBluetoothPermissions(): Boolean {
val bluetoothPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED
} else {
ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_GRANTED
}
val locationPermissions = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
return bluetoothPermissions && locationPermissions
}
private fun updateDeviceList() { private fun updateDeviceList() {
foundDevices = scanResults.map { it.device } foundDevices = scanResults.map { it.device }
@@ -559,6 +613,16 @@ class MainActivity : ComponentActivity() {
Log.d(TAG, "Saved settings deviceName=${settingsDeviceName} tab=${currentTab} mapCenter=${mapCenterPosition} zoom=${mapZoomLevel}") Log.d(TAG, "Saved settings deviceName=${settingsDeviceName} tab=${currentTab} mapCenter=${mapCenterPosition} zoom=${mapZoomLevel}")
} }
override fun onResume() {
super.onResume()
Log.d(TAG, "App resumed")
if (hasBluetoothPermissions() && !bleClient.isConnected()) {
Log.d(TAG, "App resumed and not connected, starting auto scan")
startAutoScanAndConnect()
}
}
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
saveSettings() saveSettings()
@@ -633,7 +697,8 @@ fun MainContent(
diffInSec < 3600 -> "${diffInSec / 60}分钟前" diffInSec < 3600 -> "${diffInSec / 60}分钟前"
else -> "${diffInSec / 3600}小时前" else -> "${diffInSec / 3600}小时前"
} }
delay(1000) val updateInterval = if (diffInSec < 60) 500L else if (diffInSec < 3600) 30000L else 300000L
delay(updateInterval)
} }
} else { } else {
timeSinceLastUpdate.value = null timeSinceLastUpdate.value = null

View File

@@ -86,7 +86,8 @@ fun HistoryScreen(
diffInSec < 3600 -> "${diffInSec / 60}分钟前" diffInSec < 3600 -> "${diffInSec / 60}分钟前"
else -> "${diffInSec / 3600}小时前" else -> "${diffInSec / 3600}小时前"
} }
delay(1000) val updateInterval = if (diffInSec < 60) 500L else if (diffInSec < 3600) 30000L else 300000L
delay(updateInterval)
} }
} }
} }
@@ -114,7 +115,6 @@ fun HistoryScreen(
LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) { LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) {
if (!isInEditMode) { if (!isInEditMode) {
delay(300)
val selectedIds = selectedRecordsList.map { it.timestamp.time.toString() }.toSet() val selectedIds = selectedRecordsList.map { it.timestamp.time.toString() }.toSet()
onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset)
} }
@@ -217,11 +217,37 @@ fun HistoryScreen(
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
) { ) {
val recordId = record.timestamp.time.toString() val recordId = record.timestamp.time.toString()
val isExpanded = expandedStatesMap[recordId] == true val isExpanded = expandedStatesMap[recordId] == true
val recordMap = record.toMap(showDetailedTime = isExpanded) val recordMap = record.toMap(showDetailedTime = true)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
if (recordMap.containsKey("time")) {
Column {
recordMap["time"]?.split("\n")?.forEach { timeLine ->
Text(
text = timeLine,
fontSize = 10.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
Text(
text = "${record.rssi} dBm",
fontSize = 10.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(modifier = Modifier.height(2.dp))
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -231,21 +257,6 @@ fun HistoryScreen(
val trainDisplay = val trainDisplay =
recordMap["train"]?.toString() ?: "未知列车" recordMap["train"]?.toString() ?: "未知列车"
val formattedInfo = when {
record.locoType.isNotEmpty() && record.loco.isNotEmpty() -> {
val shortLoco = if (record.loco.length > 5) {
record.loco.takeLast(5)
} else {
record.loco
}
"${record.locoType}-${shortLoco}"
}
record.locoType.isNotEmpty() -> record.locoType
record.loco.isNotEmpty() -> record.loco
else -> ""
}
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp) horizontalArrangement = Arrangement.spacedBy(6.dp)
@@ -284,30 +295,27 @@ fun HistoryScreen(
} }
} }
} }
if (formattedInfo.isNotEmpty() && formattedInfo != "<NUL>") {
Text(
text = formattedInfo,
fontSize = 14.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
} }
Text( val formattedInfo = when {
text = "${record.rssi} dBm", record.locoType.isNotEmpty() && record.loco.isNotEmpty() -> {
fontSize = 10.sp, val shortLoco = if (record.loco.length > 5) {
color = MaterialTheme.colorScheme.onSurfaceVariant record.loco.takeLast(5)
) } else {
} record.loco
}
"${record.locoType}-${shortLoco}"
}
Spacer(modifier = Modifier.height(4.dp)) record.locoType.isNotEmpty() -> record.locoType
record.loco.isNotEmpty() -> record.loco
else -> ""
}
if (recordMap.containsKey("time")) { if (formattedInfo.isNotEmpty() && formattedInfo != "<NUL>") {
recordMap["time"]?.split("\n")?.forEach { timeLine ->
Text( Text(
text = timeLine, text = formattedInfo,
fontSize = 10.sp, fontSize = 14.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }

View File

@@ -306,7 +306,7 @@ fun MapScreen(
val locationProvider = GpsMyLocationProvider(ctx).apply { val locationProvider = GpsMyLocationProvider(ctx).apply {
locationUpdateMinDistance = 10f locationUpdateMinDistance = 10f
locationUpdateMinTime = 1000 locationUpdateMinTime = 5000
} }

View File

@@ -41,7 +41,8 @@ fun MonitorScreen(
diffInSec < 3600 -> "${diffInSec / 60}分钟前" diffInSec < 3600 -> "${diffInSec / 60}分钟前"
else -> "${diffInSec / 3600}小时前" else -> "${diffInSec / 3600}小时前"
} }
delay(1000) val updateInterval = if (diffInSec < 60) 500L else if (diffInSec < 3600) 30000L else 300000L
delay(updateInterval)
} }
} }
} }