mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 19:45:25 +00:00
Refactors cleanup (#372)
* cleanup peermanager * cleanup geohash code * direct connections fix * pow display * track disconnects too * display pow only if enabled * display pow only if enabled * direct connection tracking
This commit is contained in:
@@ -248,8 +248,8 @@ fun AboutSheet(
|
||||
Slider(
|
||||
value = powDifficulty.toFloat(),
|
||||
onValueChange = { PoWPreferenceManager.setPowDifficulty(it.toInt()) },
|
||||
valueRange = 0f..20f,
|
||||
steps = 21, // 20 discrete values (0-20)
|
||||
valueRange = 0f..32f,
|
||||
steps = 33, // 33 discrete values (0-32)
|
||||
colors = SliderDefaults.colors(
|
||||
thumbColor = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D),
|
||||
activeTrackColor = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D)
|
||||
|
||||
@@ -103,6 +103,10 @@ class ChatState {
|
||||
|
||||
private val _peerRSSI = MutableLiveData<Map<String, Int>>(emptyMap())
|
||||
val peerRSSI: LiveData<Map<String, Int>> = _peerRSSI
|
||||
|
||||
// Direct connection status per peer (for live UI updates)
|
||||
private val _peerDirect = MutableLiveData<Map<String, Boolean>>(emptyMap())
|
||||
val peerDirect: LiveData<Map<String, Boolean>> = _peerDirect
|
||||
|
||||
// peerIDToPublicKeyFingerprint REMOVED - fingerprints now handled centrally in PeerManager
|
||||
|
||||
@@ -276,6 +280,10 @@ class ChatState {
|
||||
fun setPeerRSSI(rssi: Map<String, Int>) {
|
||||
_peerRSSI.value = rssi
|
||||
}
|
||||
|
||||
fun setPeerDirect(direct: Map<String, Boolean>) {
|
||||
_peerDirect.value = direct
|
||||
}
|
||||
|
||||
fun setShowAppInfo(show: Boolean) {
|
||||
_showAppInfo.value = show
|
||||
|
||||
@@ -7,6 +7,9 @@ import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Shield
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.bitchat.android.model.BitchatMessage
|
||||
import com.bitchat.android.mesh.BluetoothMeshService
|
||||
import androidx.compose.material3.ColorScheme
|
||||
@@ -124,11 +127,11 @@ fun formatMessageAsAnnotatedString(
|
||||
))
|
||||
builder.append(" [${timeFormatter.format(message.timestamp)}]")
|
||||
// If message has valid PoW difficulty, append bits immediately after timestamp with minimal spacing
|
||||
//message.powDifficulty?.let { bits ->
|
||||
// if (bits > 0) {
|
||||
// builder.append(" ${bits}b")
|
||||
// }
|
||||
//}
|
||||
message.powDifficulty?.let { bits ->
|
||||
if (bits > 0) {
|
||||
builder.append(" ⛨${bits}b")
|
||||
}
|
||||
}
|
||||
builder.pop()
|
||||
|
||||
} else {
|
||||
|
||||
@@ -106,6 +106,7 @@ class ChatViewModel(
|
||||
val peerFingerprints: LiveData<Map<String, String>> = state.peerFingerprints
|
||||
val peerNicknames: LiveData<Map<String, String>> = state.peerNicknames
|
||||
val peerRSSI: LiveData<Map<String, Int>> = state.peerRSSI
|
||||
val peerDirect: LiveData<Map<String, Boolean>> = state.peerDirect
|
||||
val showAppInfo: LiveData<Boolean> = state.showAppInfo
|
||||
val selectedLocationChannel: LiveData<com.bitchat.android.geohash.ChannelID?> = state.selectedLocationChannel
|
||||
val isTeleported: LiveData<Boolean> = state.isTeleported
|
||||
@@ -437,6 +438,14 @@ class ChatViewModel(
|
||||
|
||||
val rssiValues = meshService.getPeerRSSI()
|
||||
state.setPeerRSSI(rssiValues)
|
||||
|
||||
// Update directness per peer (driven by PeerManager state)
|
||||
try {
|
||||
val directMap = state.getConnectedPeersValue().associateWith { pid ->
|
||||
meshService.getPeerInfo(pid)?.isDirectConnection == true
|
||||
}
|
||||
state.setPeerDirect(directMap)
|
||||
} catch (_: Exception) { }
|
||||
}
|
||||
|
||||
// MARK: - Debug and Troubleshooting
|
||||
|
||||
@@ -128,67 +128,3 @@ enum class PoWIndicatorStyle {
|
||||
COMPACT, // Small icon + difficulty number
|
||||
DETAILED // Icon + status text + time estimate
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows mining progress with animated indicator
|
||||
*/
|
||||
@Composable
|
||||
fun PoWMiningIndicator(
|
||||
modifier: Modifier = Modifier,
|
||||
difficulty: Int,
|
||||
iterations: Int? = null
|
||||
) {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
color = Color(0xFFFF9500).copy(alpha = 0.1f),
|
||||
shape = androidx.compose.foundation.shape.RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// Animated security icon
|
||||
val rotation by rememberInfiniteTransition(label = "mining-rotation").animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 360f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(1000, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Restart
|
||||
),
|
||||
label = "mining-icon-rotation"
|
||||
)
|
||||
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Security,
|
||||
contentDescription = "Mining Proof of Work",
|
||||
tint = Color(0xFFFF9500),
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
.graphicsLayer { rotationZ = rotation }
|
||||
)
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "mining proof of work...",
|
||||
fontSize = 12.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color(0xFFFF9500)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "difficulty: ${difficulty}bit (~${NostrProofOfWork.estimateMiningTime(difficulty)})" +
|
||||
if (iterations != null) " • ${iterations} attempts" else "",
|
||||
fontSize = 10.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
color = colorScheme.onSurface.copy(alpha = 0.7f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,10 +384,12 @@ fun PeopleSection(
|
||||
val (bName, _) = com.bitchat.android.ui.splitSuffix(displayName)
|
||||
val showHash = (baseNameCounts[bName] ?: 0) > 1
|
||||
|
||||
val directMap by viewModel.peerDirect.observeAsState(emptyMap())
|
||||
val isDirectLive = directMap[peerID] ?: try { viewModel.meshService.getPeerInfo(peerID)?.isDirectConnection == true } catch (_: Exception) { false }
|
||||
PeerItem(
|
||||
peerID = peerID,
|
||||
displayName = displayName,
|
||||
signalStrength = convertRSSIToSignalStrength(peerRSSI[peerID]),
|
||||
isDirect = isDirectLive,
|
||||
isSelected = peerID == selectedPrivatePeer,
|
||||
isFavorite = isFavorite,
|
||||
hasUnreadDM = combinedHasUnread,
|
||||
@@ -421,7 +423,7 @@ fun PeopleSection(
|
||||
PeerItem(
|
||||
peerID = favPeerID,
|
||||
displayName = dn,
|
||||
signalStrength = 0,
|
||||
isDirect = false,
|
||||
isSelected = (mappedConnectedPeerID ?: favPeerID) == selectedPrivatePeer,
|
||||
isFavorite = true,
|
||||
hasUnreadDM = hasUnreadPrivateMessages.contains(favPeerID),
|
||||
@@ -458,15 +460,15 @@ fun PeopleSection(
|
||||
val (bName, _) = com.bitchat.android.ui.splitSuffix(dn)
|
||||
val showHash = (baseNameCounts[bName] ?: 0) > 1
|
||||
|
||||
PeerItem(
|
||||
peerID = convKey,
|
||||
displayName = dn,
|
||||
signalStrength = 0,
|
||||
isSelected = convKey == selectedPrivatePeer,
|
||||
isFavorite = false,
|
||||
hasUnreadDM = hasUnreadPrivateMessages.contains(convKey),
|
||||
colorScheme = colorScheme,
|
||||
viewModel = viewModel,
|
||||
PeerItem(
|
||||
peerID = convKey,
|
||||
displayName = dn,
|
||||
isDirect = false,
|
||||
isSelected = convKey == selectedPrivatePeer,
|
||||
isFavorite = false,
|
||||
hasUnreadDM = hasUnreadPrivateMessages.contains(convKey),
|
||||
colorScheme = colorScheme,
|
||||
viewModel = viewModel,
|
||||
onItemClick = { onPrivateChatStart(convKey) },
|
||||
onToggleFavorite = { viewModel.toggleFavorite(convKey) },
|
||||
unreadCount = privateChats[convKey]?.count { msg ->
|
||||
@@ -483,7 +485,7 @@ fun PeopleSection(
|
||||
private fun PeerItem(
|
||||
peerID: String,
|
||||
displayName: String,
|
||||
signalStrength: Int,
|
||||
isDirect: Boolean,
|
||||
isSelected: Boolean,
|
||||
isFavorite: Boolean,
|
||||
hasUnreadDM: Boolean,
|
||||
@@ -527,7 +529,7 @@ private fun PeerItem(
|
||||
tint = Color(0xFFFF9500) // iOS orange
|
||||
)
|
||||
} else {
|
||||
// Signal strength indicators
|
||||
// Connection indicator icons
|
||||
if (showNostrGlobe) {
|
||||
// Purple globe to indicate Nostr availability
|
||||
Icon(
|
||||
@@ -537,9 +539,11 @@ private fun PeerItem(
|
||||
tint = Color(0xFF9C27B0) // Purple
|
||||
)
|
||||
} else {
|
||||
SignalStrengthIndicator(
|
||||
signalStrength = signalStrength,
|
||||
colorScheme = colorScheme
|
||||
Icon(
|
||||
imageVector = if (isDirect) Icons.Outlined.SettingsInputAntenna else Icons.Filled.Route,
|
||||
contentDescription = if (isDirect) "Direct Bluetooth" else "Routed",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = colorScheme.onSurface.copy(alpha = 0.8f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user