mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 08:25:22 +00:00
wifi aware working
This commit is contained in:
@@ -100,6 +100,7 @@ class MeshDelegateHandler(
|
||||
override fun didUpdatePeerList(peers: List<String>) {
|
||||
coroutineScope.launch {
|
||||
blePeers = peers.toSet()
|
||||
try { com.bitchat.android.services.AppStateStore.setTransportPeers("BLE", peers) } catch (_: Exception) { }
|
||||
processPeerUpdate()
|
||||
}
|
||||
}
|
||||
@@ -107,16 +108,15 @@ class MeshDelegateHandler(
|
||||
fun onWifiPeersUpdated(peers: List<String>) {
|
||||
coroutineScope.launch {
|
||||
wifiPeers = peers.toSet()
|
||||
try { com.bitchat.android.services.AppStateStore.setTransportPeers("WIFI", peers) } catch (_: Exception) { }
|
||||
processPeerUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun processPeerUpdate() {
|
||||
// Merge peers from multiple transports
|
||||
val mergedPeers = (blePeers + wifiPeers).toList()
|
||||
|
||||
// Update process-wide state as source of truth
|
||||
try { com.bitchat.android.services.AppStateStore.setPeers(mergedPeers) } catch (_: Exception) { }
|
||||
val mergedPeers = com.bitchat.android.services.AppStateStore.peers.value
|
||||
.ifEmpty { (blePeers + wifiPeers).toList() }
|
||||
|
||||
state.setConnectedPeers(mergedPeers)
|
||||
state.setIsConnected(mergedPeers.isNotEmpty())
|
||||
|
||||
@@ -61,6 +61,8 @@ fun MeshPeerListSheet(
|
||||
val peerNicknames by viewModel.peerNicknames.collectAsStateWithLifecycle()
|
||||
val peerRSSI by viewModel.peerRSSI.collectAsStateWithLifecycle()
|
||||
val selectedLocationChannel by viewModel.selectedLocationChannel.collectAsStateWithLifecycle()
|
||||
val wifiAwareConnected by com.bitchat.android.wifiaware.WifiAwareController.connectedPeers.collectAsStateWithLifecycle()
|
||||
val wifiAwarePeerIDs = remember(wifiAwareConnected) { wifiAwareConnected.keys.toSet() }
|
||||
|
||||
// Bottom sheet state
|
||||
val sheetState = rememberModalBottomSheetState(
|
||||
@@ -163,11 +165,12 @@ fun MeshPeerListSheet(
|
||||
nickname = nickname,
|
||||
colorScheme = colorScheme,
|
||||
selectedPrivatePeer = selectedPrivatePeer,
|
||||
wifiAwarePeerIDs = wifiAwarePeerIDs,
|
||||
viewModel = viewModel,
|
||||
onPrivateChatStart = { peerID ->
|
||||
viewModel.showPrivateChatSheet(peerID)
|
||||
onDismiss()
|
||||
}
|
||||
onPrivateChatStart = { peerID ->
|
||||
viewModel.showPrivateChatSheet(peerID)
|
||||
onDismiss()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -279,6 +282,7 @@ fun PeopleSection(
|
||||
nickname: String,
|
||||
colorScheme: ColorScheme,
|
||||
selectedPrivatePeer: String?,
|
||||
wifiAwarePeerIDs: Set<String> = emptySet(),
|
||||
viewModel: ChatViewModel,
|
||||
onPrivateChatStart: (String) -> Unit
|
||||
) {
|
||||
@@ -416,6 +420,7 @@ fun PeopleSection(
|
||||
peerID = peerID,
|
||||
displayName = displayName,
|
||||
isDirect = isDirectLive,
|
||||
isWifiAware = peerID in wifiAwarePeerIDs,
|
||||
isSelected = peerID == selectedPrivatePeer,
|
||||
isFavorite = isFavorite,
|
||||
isVerified = isVerified,
|
||||
@@ -544,6 +549,7 @@ private fun PeerItem(
|
||||
peerID: String,
|
||||
displayName: String,
|
||||
isDirect: Boolean,
|
||||
isWifiAware: Boolean = false,
|
||||
isSelected: Boolean,
|
||||
isFavorite: Boolean,
|
||||
isVerified: Boolean,
|
||||
@@ -619,10 +625,18 @@ private fun PeerItem(
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
imageVector = if (isDirect) Icons.Outlined.Bluetooth else Icons.Filled.Route,
|
||||
contentDescription = if (isDirect) "Direct Bluetooth" else "Routed",
|
||||
imageVector = when {
|
||||
isWifiAware -> Icons.Filled.Wifi
|
||||
isDirect -> Icons.Outlined.Bluetooth
|
||||
else -> Icons.Filled.Route
|
||||
},
|
||||
contentDescription = when {
|
||||
isWifiAware -> "Direct Wi-Fi Aware"
|
||||
isDirect -> "Direct Bluetooth"
|
||||
else -> "Routed"
|
||||
},
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = colorScheme.onSurface.copy(alpha = 0.6f)
|
||||
tint = if (isWifiAware) Color(0xFF9C27B0) else colorScheme.onSurface.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -652,6 +666,16 @@ private fun PeerItem(
|
||||
color = baseColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
|
||||
if (isWifiAware && hasUnreadDM) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Wifi,
|
||||
contentDescription = "Direct Wi-Fi Aware",
|
||||
modifier = Modifier.size(13.dp),
|
||||
tint = Color(0xFF9C27B0).copy(alpha = 0.8f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,9 @@ class DebugSettingsManager private constructor() {
|
||||
DebugPreferenceManager.setBleEnabled(enabled)
|
||||
_bleEnabled.value = enabled
|
||||
addDebugMessage(DebugMessage.SystemMessage(if (enabled) "🟢 BLE enabled" else "🔴 BLE disabled"))
|
||||
try {
|
||||
com.bitchat.android.service.MeshServiceHolder.meshService?.setBleTransportEnabled(enabled)
|
||||
} catch (_: Exception) { }
|
||||
}
|
||||
|
||||
fun setWifiAwareEnabled(enabled: Boolean) {
|
||||
|
||||
@@ -42,10 +42,12 @@ import com.bitchat.android.core.ui.component.sheet.BitchatSheetTopBar
|
||||
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTitle
|
||||
|
||||
@Composable
|
||||
fun MeshTopologySection() {
|
||||
fun MeshTopologySection(localPeerID: String? = null) {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val graphService = remember { MeshGraphService.getInstance() }
|
||||
val snapshot by graphService.graphState.collectAsState()
|
||||
val wifiAwareConnected by com.bitchat.android.wifiaware.WifiAwareController.connectedPeers.collectAsState()
|
||||
val wifiAwarePeerIDs = remember(wifiAwareConnected) { wifiAwareConnected.keys.toSet() }
|
||||
|
||||
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
|
||||
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
@@ -62,6 +64,8 @@ fun MeshTopologySection() {
|
||||
ForceDirectedMeshGraph(
|
||||
nodes = nodes,
|
||||
edges = edges,
|
||||
wifiAwarePeerIDs = wifiAwarePeerIDs,
|
||||
localPeerID = localPeerID,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp)
|
||||
@@ -221,7 +225,7 @@ fun DebugSettingsSheet(
|
||||
|
||||
// Mesh topology visualization (moved below verbose logging)
|
||||
item {
|
||||
MeshTopologySection()
|
||||
MeshTopologySection(localPeerID = meshService.myPeerID)
|
||||
}
|
||||
|
||||
// GATT controls
|
||||
@@ -307,15 +311,6 @@ fun DebugSettingsSheet(
|
||||
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) {
|
||||
@@ -604,8 +599,8 @@ fun DebugSettingsSheet(
|
||||
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 = { manager.setWifiAwareEnabled(true) }, label = { Text("Start") })
|
||||
AssistChip(onClick = { manager.setWifiAwareEnabled(false) }, 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)
|
||||
|
||||
@@ -4,6 +4,11 @@ import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.gestures.detectDragGestures
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Wifi
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
@@ -14,6 +19,7 @@ import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.bitchat.android.services.meshgraph.MeshGraphService
|
||||
@@ -212,6 +218,8 @@ private class Simulation {
|
||||
fun ForceDirectedMeshGraph(
|
||||
nodes: List<MeshGraphService.GraphNode>,
|
||||
edges: List<MeshGraphService.GraphEdge>,
|
||||
wifiAwarePeerIDs: Set<String> = emptySet(),
|
||||
localPeerID: String? = null,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
@@ -405,5 +413,46 @@ fun ForceDirectedMeshGraph(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val iconSize = 16.dp
|
||||
val iconSizePx = with(density) { iconSize.toPx() }
|
||||
val halfIconSizePx = iconSizePx / 2f
|
||||
val localID = localPeerID
|
||||
val shouldMarkWifiEdge: (MeshGraphService.GraphEdge) -> Boolean = { edge ->
|
||||
if (localID != null) {
|
||||
(edge.a == localID && edge.b in wifiAwarePeerIDs) ||
|
||||
(edge.b == localID && edge.a in wifiAwarePeerIDs)
|
||||
} else {
|
||||
edge.a in wifiAwarePeerIDs || edge.b in wifiAwarePeerIDs
|
||||
}
|
||||
}
|
||||
|
||||
val wifiEdgeMidpoints = tick.let {
|
||||
simulation.edges.mapNotNull { edge ->
|
||||
val n1 = simulation.nodes[edge.a]
|
||||
val n2 = simulation.nodes[edge.b]
|
||||
if (n1 != null && n2 != null && shouldMarkWifiEdge(edge)) {
|
||||
((n1.x + n2.x) / 2f) to ((n1.y + n2.y) / 2f)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wifiEdgeMidpoints.forEach { (midX, midY) ->
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Wifi,
|
||||
contentDescription = null,
|
||||
tint = Color(0xFF9C27B0).copy(alpha = 0.82f),
|
||||
modifier = Modifier
|
||||
.offset {
|
||||
IntOffset(
|
||||
x = (midX - halfIconSizePx).roundToInt(),
|
||||
y = (midY - halfIconSizePx).roundToInt()
|
||||
)
|
||||
}
|
||||
.size(iconSize)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user