diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/BluetoothSettingsTab.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/BluetoothSettingsTab.kt index ae120b27..ce2516e6 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/BluetoothSettingsTab.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/BluetoothSettingsTab.kt @@ -32,7 +32,7 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext import org.json.JSONArray -private data class BluetoothPeer(val id: String, val name: String, val address: String, val rssi: Int) +private data class BluetoothPeer(val id: String, val name: String, val address: String, val rssi: Int, val broadcasts: Long) /** Снимок DataStore без чтения диска на main; принятые записи принадлежат Application. * Разрешения/включение адаптера подтверждаются Android, ошибки запуска показываются в этой вкладке. */ @@ -62,7 +62,8 @@ fun BluetoothSettingsTab() { val snapshot = JSONArray(NativeLib.getBluetoothPeers()) List(snapshot.length()) { i -> val peer = snapshot.getJSONObject(i) - BluetoothPeer(peer.getString("id"), peer.getString("name"), peer.getString("address"), peer.getInt("rssi")) + BluetoothPeer(peer.getString("id"), peer.getString("name"), peer.getString("address"), + peer.getInt("rssi"), peer.getLong("broadcasts")) }.sortedWith(compareBy { it.name }.thenBy { it.id }) } peersFailed = false @@ -133,8 +134,13 @@ fun BluetoothSettingsTab() { key(peer.id) { Row(Modifier.fillMaxWidth().padding(vertical = 3.dp), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) { - Text(peer.name.ifEmpty { peer.id }, Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium, - lineHeight = 16.sp, maxLines = 2, overflow = TextOverflow.Ellipsis) + Column(Modifier.weight(1f)) { + Text(peer.name.ifEmpty { peer.id }, style = MaterialTheme.typography.bodyMedium, + lineHeight = 16.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) + Text(stringResource(R.string.ble_broadcast_received, peer.broadcasts), + color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.bodySmall, + lineHeight = 16.sp, maxLines = 1, softWrap = false) + } SelectionContainer { Column { Text(peer.id, color = MaterialTheme.colorScheme.primary, fontFamily = FontFamily.Monospace, diff --git a/tools/chatgui-android/jni_bridge/android_jni_bridge.c b/tools/chatgui-android/jni_bridge/android_jni_bridge.c index b1870544..52759dfe 100644 --- a/tools/chatgui-android/jni_bridge/android_jni_bridge.c +++ b/tools/chatgui-android/jni_bridge/android_jni_bridge.c @@ -1598,7 +1598,7 @@ static jobject g_event_callback = NULL; static jmethodID g_event_mid = NULL; static pthread_mutex_t g_event_callback_lock = PTHREAD_MUTEX_INITIALIZER; -/* Только worker: свежая таблица BLE, включая текущий адрес объявления и неизвестный RSSI=127. */ +/* Только worker: свежая таблица BLE с адресом, RSSI=127 при неизвестном значении и счётчиком объявлений. */ static char* bluetooth_peers_json(void) { struct ble_neighbor peers[BLE_NEIGHBORS_MAX]; size_t count = ble_etcp_neighbors(android_ble_driver(), peers, BLE_NEIGHBORS_MAX); @@ -1608,7 +1608,8 @@ static char* bluetooth_peers_json(void) { const struct ble_neighbor* p = &peers[i]; if (strbuf_addf(&out, "%s{\"id\":\"%016llx\",\"name\":", i ? "," : "", (unsigned long long)p->identity.node_id) < 0 || strbuf_add_json_string(&out, p->identity.name) < 0 || strbuf_addf(&out, ",\"address\":") < 0 || - strbuf_add_json_string(&out, p->endpoint.id) < 0 || strbuf_addf(&out, ",\"rssi\":%d}", p->rssi) < 0) goto failed; + strbuf_add_json_string(&out, p->endpoint.id) < 0 || + strbuf_addf(&out, ",\"rssi\":%d,\"broadcasts\":%llu}", p->rssi, (unsigned long long)p->broadcast_received) < 0) goto failed; } if (strbuf_addf(&out, "]") < 0) goto failed; DEBUG_DEBUG(DEBUG_CATEGORY_DISCOVERY, "BLE devices snapshot count=%zu", count);