mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 12:05:20 +00:00
fix: wifi aware socket binding (#533)
* wifi aware wip * wifi aware wip * starting to work * werk * dms work * wip * fix(wifi-aware): use bindSocket and scoped IPv6 instead of bindProcessToNetwork * Merge branch 'upstream/main' into fix/wifi-aware-socket-binding * Fix Wi-Fi Aware connectivity and UI integration post-merge - Replace bindProcessToNetwork with bindSocket for VPN compatibility. - Implement Scoped IPv6 address resolution (aware0) for mesh routing. - Bridge Wi-Fi Aware incoming messages to AppStateStore for UI visibility. - Fix syntax errors and variable name conflicts in Debug UI. * Enhance Wi-Fi Aware robustness and debug UI display - Clean up transport resources (sockets, server sockets, network callbacks) immediately on peer disconnection. - Implement resolveScopedAddress to show scoped IPv6 (e.g., %aware0) in Debug UI. - Fix Map type mismatch warning in ChatViewModel bridge. - Filter self-ID from peer cleanup tables to prevent recursive self-removal. * Share GossipSyncManager across transports to prevent redundant message synchronization - Registered BluetoothMeshService's GossipSyncManager as a singleton in MeshServiceHolder. - Modified WifiAwareMeshService to use the shared GossipSyncManager if available. - Added background cleanup for peer mappings on socket disconnection. - Fixed Kotlin type mismatch during nickname map merging. * Restore VPN acquisition logic and improve peer cleanup - Revert removal of NET_CAPABILITY_NOT_VPN to allow hardware handle acquisition while VPN is active. - Refactor handlePeerDisconnection to more reliably cleanup initial and routed IDs. - Switch cleanup logging to debug level to reduce log noise. --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> Co-authored-by: aidenvalue <>
This commit is contained in:
co-authored by
callebtc
aidenvalue <>
parent
903a4584a8
commit
0c7505b588
@@ -441,8 +441,9 @@ class ChatViewModel(
|
||||
state.getNicknameValue()
|
||||
)
|
||||
} else {
|
||||
// Default: route via mesh
|
||||
// Default: route via mesh + Wi‑Fi Aware
|
||||
meshService.sendMessage(messageContent, mentions, channel)
|
||||
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendMessage(messageContent, mentions, channel) } catch (_: Exception) {}
|
||||
}
|
||||
})
|
||||
return
|
||||
@@ -512,19 +513,23 @@ class ChatViewModel(
|
||||
state.getNicknameValue(),
|
||||
meshService.myPeerID,
|
||||
onEncryptedPayload = { encryptedData ->
|
||||
// This would need proper mesh service integration
|
||||
// Send encrypted payload announcement over both transports for reachability
|
||||
meshService.sendMessage(content, mentions, currentChannelValue)
|
||||
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendMessage(content, mentions, currentChannelValue) } catch (_: Exception) {}
|
||||
},
|
||||
onFallback = {
|
||||
meshService.sendMessage(content, mentions, currentChannelValue)
|
||||
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendMessage(content, mentions, currentChannelValue) } catch (_: Exception) {}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
meshService.sendMessage(content, mentions, currentChannelValue)
|
||||
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendMessage(content, mentions, currentChannelValue) } catch (_: Exception) {}
|
||||
}
|
||||
} else {
|
||||
messageManager.addMessage(message)
|
||||
meshService.sendMessage(content, mentions, null)
|
||||
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendMessage(content, mentions, null) } catch (_: Exception) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -647,16 +652,23 @@ class ChatViewModel(
|
||||
val fingerprints = privateChatManager.getAllPeerFingerprints()
|
||||
state.setPeerFingerprints(fingerprints)
|
||||
|
||||
val nicknames = meshService.getPeerNicknames()
|
||||
state.setPeerNicknames(nicknames)
|
||||
// Merge nicknames from BLE and Wi‑Fi Aware to display names for all peers
|
||||
val bleNick = meshService.getPeerNicknames()
|
||||
val awareNickRaw = try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.getPeerNicknamesMap() } catch (_: Exception) { null }
|
||||
val mergedNick = if (awareNickRaw != null) bleNick + awareNickRaw.filter { it.value != null }.mapValues { it.value!! }.filterKeys { it !in bleNick || bleNick[it].isNullOrBlank() } else bleNick
|
||||
state.setPeerNicknames(mergedNick)
|
||||
|
||||
val rssiValues = meshService.getPeerRSSI()
|
||||
state.setPeerRSSI(rssiValues)
|
||||
val awareRssi = try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.getPeerRSSI() } catch (_: Exception) { null }
|
||||
val mergedRssi = if (awareRssi != null) rssiValues + awareRssi.filterKeys { it !in rssiValues } else rssiValues
|
||||
state.setPeerRSSI(mergedRssi)
|
||||
|
||||
// Update directness per peer (driven by PeerManager state)
|
||||
try {
|
||||
val directMap = state.getConnectedPeersValue().associateWith { pid ->
|
||||
meshService.getPeerInfo(pid)?.isDirectConnection == true
|
||||
val ble = meshService.getPeerInfo(pid)?.isDirectConnection == true
|
||||
val aware = try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.getPeerInfo(pid)?.isDirectConnection == true } catch (_: Exception) { false }
|
||||
ble || aware
|
||||
}
|
||||
state.setPeerDirect(directMap)
|
||||
} catch (_: Exception) { }
|
||||
|
||||
@@ -210,6 +210,7 @@ class MediaSendingManager(
|
||||
|
||||
Log.d(TAG, "📤 Calling meshService.sendFilePrivate to $toPeerID")
|
||||
meshService.sendFilePrivate(toPeerID, filePacket)
|
||||
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendFilePrivate(toPeerID, filePacket) } catch (_: Exception) {}
|
||||
Log.d(TAG, "✅ File send completed successfully")
|
||||
}
|
||||
|
||||
@@ -264,6 +265,7 @@ class MediaSendingManager(
|
||||
|
||||
Log.d(TAG, "📤 Calling meshService.sendFileBroadcast")
|
||||
meshService.sendFileBroadcast(filePacket)
|
||||
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendFileBroadcast(filePacket) } catch (_: Exception) {}
|
||||
Log.d(TAG, "✅ File broadcast completed successfully")
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,10 @@ class MeshDelegateHandler(
|
||||
|
||||
override fun didUpdatePeerList(peers: List<String>) {
|
||||
coroutineScope.launch {
|
||||
state.setConnectedPeers(peers)
|
||||
// Merge peers from multiple transports to avoid flapping
|
||||
val current = state.getConnectedPeersValue().toMutableSet()
|
||||
current.addAll(peers)
|
||||
state.setConnectedPeers(current.toList())
|
||||
state.setIsConnected(peers.isNotEmpty())
|
||||
notificationManager.showActiveUserNotification(peers)
|
||||
// Flush router outbox for any peers that just connected (and their noiseHex aliases)
|
||||
|
||||
@@ -576,9 +576,26 @@ private fun PeerItem(
|
||||
tint = Color.Gray
|
||||
)
|
||||
} else {
|
||||
val awareConnected by com.bitchat.android.wifiaware.WifiAwareController.connectedPeers.collectAsState()
|
||||
val awareDiscovered by com.bitchat.android.wifiaware.WifiAwareController.discoveredPeers.collectAsState()
|
||||
val isWifiDirect = awareConnected.containsKey(peerID)
|
||||
val isBleDirect = isDirect
|
||||
val icon = when {
|
||||
isWifiDirect -> Icons.Filled.Wifi
|
||||
isBleDirect -> Icons.Outlined.SettingsInputAntenna
|
||||
// Routed: show Route icon; optionally prefer Wi‑Fi Aware if discovered there
|
||||
awareDiscovered.contains(peerID) -> Icons.Filled.WifiTethering
|
||||
else -> Icons.Filled.Route
|
||||
}
|
||||
val cd = when {
|
||||
isWifiDirect -> "Direct Wi‑Fi Aware"
|
||||
isBleDirect -> "Direct Bluetooth"
|
||||
awareDiscovered.contains(peerID) -> "Routed over Wi‑Fi"
|
||||
else -> "Routed"
|
||||
}
|
||||
Icon(
|
||||
imageVector = if (isDirect) Icons.Outlined.SettingsInputAntenna else Icons.Filled.Route,
|
||||
contentDescription = if (isDirect) "Direct Bluetooth" else "Routed",
|
||||
imageVector = icon,
|
||||
contentDescription = cd,
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = colorScheme.onSurface.copy(alpha = 0.8f)
|
||||
)
|
||||
|
||||
@@ -20,7 +20,10 @@ object DebugPreferenceManager {
|
||||
// GCS keys (no migration/back-compat)
|
||||
private const val KEY_GCS_MAX_BYTES = "gcs_max_filter_bytes"
|
||||
private const val KEY_GCS_FPR = "gcs_filter_fpr_percent"
|
||||
// Removed: persistent notification toggle is now governed by MeshServicePreferences.isBackgroundEnabled
|
||||
// Transport master toggles
|
||||
private const val KEY_BLE_ENABLED = "ble_enabled"
|
||||
private const val KEY_WIFI_AWARE_ENABLED = "wifi_aware_enabled"
|
||||
private const val KEY_WIFI_AWARE_VERBOSE = "wifi_aware_verbose"
|
||||
|
||||
private lateinit var prefs: SharedPreferences
|
||||
|
||||
@@ -102,5 +105,25 @@ object DebugPreferenceManager {
|
||||
if (ready()) prefs.edit().putLong(KEY_GCS_FPR, java.lang.Double.doubleToRawLongBits(value)).apply()
|
||||
}
|
||||
|
||||
// No longer storing persistent notification in debug prefs.
|
||||
// Transport toggles
|
||||
fun getBleEnabled(default: Boolean = true): Boolean =
|
||||
if (ready()) prefs.getBoolean(KEY_BLE_ENABLED, default) else default
|
||||
|
||||
fun setBleEnabled(value: Boolean) {
|
||||
if (ready()) prefs.edit().putBoolean(KEY_BLE_ENABLED, value).apply()
|
||||
}
|
||||
|
||||
fun getWifiAwareEnabled(default: Boolean = false): Boolean =
|
||||
if (ready()) prefs.getBoolean(KEY_WIFI_AWARE_ENABLED, default) else default
|
||||
|
||||
fun setWifiAwareEnabled(value: Boolean) {
|
||||
if (ready()) prefs.edit().putBoolean(KEY_WIFI_AWARE_ENABLED, value).apply()
|
||||
}
|
||||
|
||||
fun getWifiAwareVerbose(default: Boolean = false): Boolean =
|
||||
if (ready()) prefs.getBoolean(KEY_WIFI_AWARE_VERBOSE, default) else default
|
||||
|
||||
fun setWifiAwareVerbose(value: Boolean) {
|
||||
if (ready()) prefs.edit().putBoolean(KEY_WIFI_AWARE_VERBOSE, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,17 @@ class DebugSettingsManager private constructor() {
|
||||
private val _packetRelayEnabled = MutableStateFlow(true)
|
||||
val packetRelayEnabled: StateFlow<Boolean> = _packetRelayEnabled.asStateFlow()
|
||||
|
||||
// Master transport toggles
|
||||
private val _bleEnabled = MutableStateFlow(true)
|
||||
val bleEnabled: StateFlow<Boolean> = _bleEnabled.asStateFlow()
|
||||
|
||||
private val _wifiAwareEnabled = MutableStateFlow(false)
|
||||
val wifiAwareEnabled: StateFlow<Boolean> = _wifiAwareEnabled.asStateFlow()
|
||||
|
||||
// Master transport toggles
|
||||
private val _wifiAwareVerbose = MutableStateFlow(false)
|
||||
val wifiAwareVerbose: StateFlow<Boolean> = _wifiAwareVerbose.asStateFlow()
|
||||
|
||||
// Visibility of the debug sheet; gates heavy work
|
||||
private val _debugSheetVisible = MutableStateFlow(false)
|
||||
val debugSheetVisible: StateFlow<Boolean> = _debugSheetVisible.asStateFlow()
|
||||
@@ -59,6 +70,10 @@ class DebugSettingsManager private constructor() {
|
||||
_maxConnectionsOverall.value = DebugPreferenceManager.getMaxConnectionsOverall(8)
|
||||
_maxServerConnections.value = DebugPreferenceManager.getMaxConnectionsServer(8)
|
||||
_maxClientConnections.value = DebugPreferenceManager.getMaxConnectionsClient(8)
|
||||
// Transport toggles
|
||||
_bleEnabled.value = DebugPreferenceManager.getBleEnabled(true)
|
||||
_wifiAwareEnabled.value = DebugPreferenceManager.getWifiAwareEnabled(false)
|
||||
_wifiAwareVerbose.value = DebugPreferenceManager.getWifiAwareVerbose(false)
|
||||
} catch (_: Exception) {
|
||||
// Preferences not ready yet; keep defaults. They will be applied on first change.
|
||||
}
|
||||
@@ -262,6 +277,27 @@ class DebugSettingsManager private constructor() {
|
||||
))
|
||||
}
|
||||
|
||||
fun setBleEnabled(enabled: Boolean) {
|
||||
DebugPreferenceManager.setBleEnabled(enabled)
|
||||
_bleEnabled.value = enabled
|
||||
addDebugMessage(DebugMessage.SystemMessage(if (enabled) "🟢 BLE enabled" else "🔴 BLE disabled"))
|
||||
}
|
||||
|
||||
fun setWifiAwareEnabled(enabled: Boolean) {
|
||||
DebugPreferenceManager.setWifiAwareEnabled(enabled)
|
||||
_wifiAwareEnabled.value = enabled
|
||||
addDebugMessage(DebugMessage.SystemMessage(if (enabled) "🟢 Wi‑Fi Aware enabled" else "🔴 Wi‑Fi Aware disabled"))
|
||||
try {
|
||||
com.bitchat.android.wifiaware.WifiAwareController.setEnabled(enabled)
|
||||
} catch (_: Exception) { }
|
||||
}
|
||||
|
||||
fun setWifiAwareVerbose(enabled: Boolean) {
|
||||
DebugPreferenceManager.setWifiAwareVerbose(enabled)
|
||||
_wifiAwareVerbose.value = enabled
|
||||
addDebugMessage(DebugMessage.SystemMessage(if (enabled) "🔊 Wi‑Fi Aware verbose logging enabled" else "🔇 Wi‑Fi Aware verbose logging disabled"))
|
||||
}
|
||||
|
||||
fun setMaxConnectionsOverall(value: Int) {
|
||||
val clamped = value.coerceIn(1, 32)
|
||||
DebugPreferenceManager.setMaxConnectionsOverall(clamped)
|
||||
@@ -319,6 +355,16 @@ class DebugSettingsManager private constructor() {
|
||||
fun updateConnectedDevices(devices: List<ConnectedDevice>) {
|
||||
_connectedDevices.value = devices
|
||||
}
|
||||
|
||||
// Wi‑Fi Aware debug collections
|
||||
private val _wifiAwareDiscovered = MutableStateFlow<Map<String, String>>(emptyMap()) // peerID->nickname
|
||||
val wifiAwareDiscovered: StateFlow<Map<String, String>> = _wifiAwareDiscovered.asStateFlow()
|
||||
|
||||
private val _wifiAwareConnected = MutableStateFlow<Map<String, String>>(emptyMap()) // peerID->ip
|
||||
val wifiAwareConnected: StateFlow<Map<String, String>> = _wifiAwareConnected.asStateFlow()
|
||||
|
||||
fun updateWifiAwareDiscovered(map: Map<String, String>) { _wifiAwareDiscovered.value = map }
|
||||
fun updateWifiAwareConnected(map: Map<String, String>) { _wifiAwareConnected.value = map }
|
||||
|
||||
fun updateRelayStats(stats: PacketRelayStats) {
|
||||
_relayStats.value = stats
|
||||
|
||||
@@ -10,6 +10,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Bluetooth
|
||||
import androidx.compose.material.icons.filled.Wifi
|
||||
import androidx.compose.material.icons.filled.WifiTethering
|
||||
import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.material.icons.filled.Cancel
|
||||
import androidx.compose.material.icons.filled.Devices
|
||||
@@ -50,7 +52,7 @@ fun DebugSettingsSheet(
|
||||
val verboseLogging by manager.verboseLoggingEnabled.collectAsState()
|
||||
val gattServerEnabled by manager.gattServerEnabled.collectAsState()
|
||||
val gattClientEnabled by manager.gattClientEnabled.collectAsState()
|
||||
val packetRelayEnabled by manager.packetRelayEnabled.collectAsState()
|
||||
val packetRelayed by manager.packetRelayEnabled.collectAsState()
|
||||
val maxOverall by manager.maxConnectionsOverall.collectAsState()
|
||||
val maxServer by manager.maxServerConnections.collectAsState()
|
||||
val maxClient by manager.maxClientConnections.collectAsState()
|
||||
@@ -62,6 +64,12 @@ fun DebugSettingsSheet(
|
||||
val gcsMaxBytes by manager.gcsMaxBytes.collectAsState()
|
||||
val gcsFpr by manager.gcsFprPercent.collectAsState()
|
||||
val context = LocalContext.current
|
||||
|
||||
val bleEnabled by manager.bleEnabled.collectAsState()
|
||||
val wifiAwareEnabled by manager.wifiAwareEnabled.collectAsState()
|
||||
val wifiAwareVerbose by manager.wifiAwareVerbose.collectAsState()
|
||||
val wifiAwareDiscovered by manager.wifiAwareDiscovered.collectAsState()
|
||||
val wifiAwareConnected by manager.wifiAwareConnected.collectAsState()
|
||||
// Persistent notification is now controlled solely by MeshServicePreferences.isBackgroundEnabled
|
||||
|
||||
// Push live connected devices from mesh service whenever sheet is visible
|
||||
@@ -86,6 +94,15 @@ fun DebugSettingsSheet(
|
||||
)
|
||||
}
|
||||
manager.updateConnectedDevices(devices)
|
||||
// Also surface Wi‑Fi Aware status
|
||||
try {
|
||||
val ctrl = com.bitchat.android.wifiaware.WifiAwareController
|
||||
val known = ctrl.knownPeers.value
|
||||
val discovered = ctrl.discoveredPeers.value
|
||||
val discoveredMap = discovered.associateWith { pid -> known[pid] ?: "" }
|
||||
manager.updateWifiAwareDiscovered(discoveredMap)
|
||||
manager.updateWifiAwareConnected(ctrl.connectedPeers.value)
|
||||
} catch (_: Exception) { }
|
||||
kotlinx.coroutines.delay(1000)
|
||||
}
|
||||
}
|
||||
@@ -213,6 +230,46 @@ fun DebugSettingsSheet(
|
||||
}
|
||||
}
|
||||
|
||||
// Transport toggles (BLE + Wi‑Fi Aware)
|
||||
item {
|
||||
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
|
||||
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Icon(Icons.Filled.Devices, contentDescription = null, tint = Color(0xFF4CAF50))
|
||||
Text("Transports", fontFamily = FontFamily.Monospace, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(Icons.Filled.Bluetooth, contentDescription = null, tint = Color(0xFF007AFF))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text("BLE", fontFamily = FontFamily.Monospace, modifier = Modifier.weight(1f))
|
||||
Switch(checked = bleEnabled, onCheckedChange = {
|
||||
manager.setBleEnabled(it)
|
||||
scope.launch {
|
||||
if (it) {
|
||||
if (gattServerEnabled) meshService.connectionManager.startServer()
|
||||
if (gattClientEnabled) meshService.connectionManager.startClient()
|
||||
} else {
|
||||
meshService.connectionManager.stopServer()
|
||||
meshService.connectionManager.stopClient()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(Icons.Filled.Wifi, contentDescription = null, tint = Color(0xFF9C27B0))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text("Wi‑Fi Aware", fontFamily = FontFamily.Monospace, modifier = Modifier.weight(1f))
|
||||
Switch(checked = wifiAwareEnabled, onCheckedChange = { manager.setWifiAwareEnabled(it) })
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Spacer(Modifier.width(24.dp))
|
||||
Text("Wi‑Fi Aware verbose", fontFamily = FontFamily.Monospace, modifier = Modifier.weight(1f))
|
||||
Switch(checked = wifiAwareVerbose, onCheckedChange = { manager.setWifiAwareVerbose(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Packet relay controls and stats
|
||||
item {
|
||||
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
|
||||
@@ -223,7 +280,7 @@ fun DebugSettingsSheet(
|
||||
Icon(Icons.Filled.PowerSettingsNew, contentDescription = null, tint = Color(0xFFFF9500))
|
||||
Text(stringResource(R.string.debug_packet_relay), fontFamily = FontFamily.Monospace, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||
Spacer(Modifier.weight(1f))
|
||||
Switch(checked = packetRelayEnabled, onCheckedChange = { manager.setPacketRelayEnabled(it) })
|
||||
Switch(checked = packetRelayed, onCheckedChange = { manager.setPacketRelayEnabled(it) })
|
||||
}
|
||||
// Removed aggregate labels; we will show per-direction compact labels below titles
|
||||
// Toggle: overall vs per-connection vs per-peer
|
||||
@@ -472,6 +529,43 @@ fun DebugSettingsSheet(
|
||||
}
|
||||
}
|
||||
|
||||
// Wi‑Fi Aware controls and status
|
||||
item {
|
||||
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
|
||||
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Icon(Icons.Filled.WifiTethering, contentDescription = null, tint = Color(0xFF9C27B0))
|
||||
Text("Wi‑Fi Aware", fontFamily = FontFamily.Monospace, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||
Spacer(Modifier.weight(1f))
|
||||
val running by com.bitchat.android.wifiaware.WifiAwareController.running.collectAsState()
|
||||
Text(if (running) "running" else "stopped", fontFamily = FontFamily.Monospace, fontSize = 12.sp, color = colorScheme.onSurface.copy(alpha = 0.7f))
|
||||
}
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
AssistChip(onClick = { com.bitchat.android.wifiaware.WifiAwareController.startIfPossible() }, label = { Text("Start") })
|
||||
AssistChip(onClick = { com.bitchat.android.wifiaware.WifiAwareController.stop() }, label = { Text("Stop") })
|
||||
AssistChip(onClick = { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendBroadcastAnnounce() }, label = { Text("Announce") })
|
||||
}
|
||||
Text("Discovered: ${wifiAwareDiscovered.size}", fontFamily = FontFamily.Monospace, fontSize = 12.sp)
|
||||
if (wifiAwareDiscovered.isEmpty()) {
|
||||
Text("No discoveries yet", fontFamily = FontFamily.Monospace, fontSize = 11.sp, color = colorScheme.onSurface.copy(alpha = 0.6f))
|
||||
} else {
|
||||
wifiAwareDiscovered.entries.take(50).forEach { (peer, nick) ->
|
||||
Text("• ${if (nick.isBlank()) peer.take(8) + "…" else nick} (${peer.take(8)}…) ", fontFamily = FontFamily.Monospace, fontSize = 12.sp)
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
Text("Connected: ${wifiAwareConnected.size}", fontFamily = FontFamily.Monospace, fontSize = 12.sp)
|
||||
if (wifiAwareConnected.isEmpty()) {
|
||||
Text("No active sockets", fontFamily = FontFamily.Monospace, fontSize = 11.sp, color = colorScheme.onSurface.copy(alpha = 0.6f))
|
||||
} else {
|
||||
wifiAwareConnected.entries.take(50).forEach { (peer, ip) ->
|
||||
Text("• ${peer.take(8)}… @ $ip", fontFamily = FontFamily.Monospace, fontSize = 12.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connected devices
|
||||
item {
|
||||
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
|
||||
|
||||
Reference in New Issue
Block a user