nostr: fix block feature (#427)

* fix block feature

* fix nostr nickname in sidebar
This commit is contained in:
callebtc
2025-09-14 17:30:47 +02:00
committed by GitHub
parent a4ef2ef29c
commit 277dbdf4e1
5 changed files with 64 additions and 32 deletions
@@ -22,7 +22,8 @@ class GeohashMessageHandler(
private val state: ChatState,
private val messageManager: MessageManager,
private val repo: GeohashRepository,
private val scope: CoroutineScope
private val scope: CoroutineScope,
private val dataManager: com.bitchat.android.ui.DataManager
) {
companion object { private const val TAG = "GeohashMessageHandler" }
@@ -56,8 +57,8 @@ class GeohashMessageHandler(
if (!NostrProofOfWork.validateDifficulty(event, pow.difficulty)) return@launch
}
// Blocked users check
if (com.bitchat.android.ui.DataManager(application).isGeohashUserBlocked(event.pubkey)) return@launch
// Blocked users check (use injected DataManager which has loaded state)
if (dataManager.isGeohashUserBlocked(event.pubkey)) return@launch
// Update repository (participants, nickname, teleport)
// Update repository on a background-safe path; repository will post updates to LiveData
@@ -14,7 +14,8 @@ import java.util.Date
*/
class GeohashRepository(
private val application: Application,
private val state: ChatState
private val state: ChatState,
private val dataManager: com.bitchat.android.ui.DataManager
) {
companion object { private const val TAG = "GeohashRepository" }
@@ -103,7 +104,8 @@ class GeohashRepository(
val e = it.next()
if (e.value.before(cutoff)) it.remove()
}
return participants.size
// exclude blocked users
return participants.keys.count { !dataManager.isGeohashUserBlocked(it) }
}
fun refreshGeohashPeople() {
@@ -122,8 +124,18 @@ class GeohashRepository(
if (e.value.before(cutoff)) it.remove()
}
geohashParticipants[geohash] = participants
val people = participants.map { (pubkeyHex, lastSeen) ->
val base = getCachedNickname(pubkeyHex) ?: "anon"
// exclude blocked users from people list
val people = participants.filterKeys { !dataManager.isGeohashUserBlocked(it) }
.map { (pubkeyHex, lastSeen) ->
// Use our actual nickname for self; otherwise use cached nickname or anon
val base = try {
val myHex = currentGeohash?.let { NostrIdentityBridge.deriveIdentity(it, application).publicKeyHex }
if (myHex != null && myHex.equals(pubkeyHex, true)) {
state.getNicknameValue() ?: "anon"
} else {
getCachedNickname(pubkeyHex) ?: "anon"
}
} catch (_: Exception) { getCachedNickname(pubkeyHex) ?: "anon" }
GeoPerson(
id = pubkeyHex.lowercase(),
displayName = base, // UI can add #hash if necessary
@@ -138,7 +150,8 @@ class GeohashRepository(
val cutoff = Date(System.currentTimeMillis() - 5 * 60 * 1000)
val counts = mutableMapOf<String, Int>()
for ((gh, participants) in geohashParticipants) {
val active = participants.values.count { !it.before(cutoff) }
val active = participants.filterKeys { !dataManager.isGeohashUserBlocked(it) }
.values.count { !it.before(cutoff) }
counts[gh] = active
}
// Use postValue for thread safety - this can be called from background threads
@@ -186,6 +199,7 @@ class GeohashRepository(
val participants = geohashParticipants[current] ?: emptyMap()
var count = 0
for ((k, t) in participants) {
if (dataManager.isGeohashUserBlocked(k)) continue
if (t.before(cutoff)) continue
val name = if (k.equals(lower, true)) base else (geoNicknames[k.lowercase()] ?: "anon")
if (name.equals(base, true)) { count++; if (count > 1) break }
@@ -207,6 +221,7 @@ class GeohashRepository(
val participants = geohashParticipants[sourceGeohash] ?: emptyMap()
var count = 0
for ((k, t) in participants) {
if (dataManager.isGeohashUserBlocked(k)) continue
if (t.before(cutoff)) continue
val name = if (k.equals(lower, true)) base else (geoNicknames[k.lowercase()] ?: "anon")
if (name.equals(base, true)) { count++; if (count > 1) break }
@@ -21,7 +21,8 @@ class NostrDirectMessageHandler(
private val privateChatManager: PrivateChatManager,
private val meshDelegateHandler: MeshDelegateHandler,
private val scope: CoroutineScope,
private val repo: GeohashRepository
private val repo: GeohashRepository,
private val dataManager: com.bitchat.android.ui.DataManager
) {
companion object { private const val TAG = "NostrDirectMessageHandler" }
@@ -58,6 +59,10 @@ class NostrDirectMessageHandler(
}
val (content, senderPubkey, rumorTimestamp) = decryptResult
// If sender is blocked for geohash contexts, drop any events from this pubkey
// Applies to both geohash DMs (geohash != "") and account DMs (geohash == "")
if (dataManager.isGeohashUserBlocked(senderPubkey)) return@launch
if (!content.startsWith("bitchat1:")) return@launch
val base64Content = content.removePrefix("bitchat1:")
@@ -415,7 +415,7 @@ fun AboutSheet(
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text("Tor On", fontFamily = FontFamily.Monospace)
Text("tor on", fontFamily = FontFamily.Monospace)
val statusColor = when {
torStatus.running && torStatus.bootstrapPercent < 100 -> Color(0xFFFF9500)
torStatus.running && torStatus.bootstrapPercent >= 100 -> if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D)
@@ -30,10 +30,25 @@ class GeohashViewModel(
companion object { private const val TAG = "GeohashViewModel" }
private val repo = GeohashRepository(application, state)
private val repo = GeohashRepository(application, state, dataManager)
private val subscriptionManager = NostrSubscriptionManager(application, viewModelScope)
private val geohashMessageHandler = GeohashMessageHandler(application, state, messageManager, repo, viewModelScope)
private val dmHandler = NostrDirectMessageHandler(application, state, privateChatManager, meshDelegateHandler, viewModelScope, repo)
private val geohashMessageHandler = GeohashMessageHandler(
application = application,
state = state,
messageManager = messageManager,
repo = repo,
scope = viewModelScope,
dataManager = dataManager
)
private val dmHandler = NostrDirectMessageHandler(
application = application,
state = state,
privateChatManager = privateChatManager,
meshDelegateHandler = meshDelegateHandler,
scope = viewModelScope,
repo = repo,
dataManager = dataManager
)
private var currentGeohashSubId: String? = null
private var currentDmSubId: String? = null
@@ -141,25 +156,6 @@ class GeohashViewModel(
fun geohashParticipantCount(geohash: String): Int = repo.geohashParticipantCount(geohash)
fun isPersonTeleported(pubkeyHex: String): Boolean = repo.isPersonTeleported(pubkeyHex)
fun startGeohashDM(pubkeyHex: String, onStartPrivateChat: (String) -> Unit) {
val convKey = "nostr_${pubkeyHex.take(16)}"
repo.putNostrKeyMapping(convKey, pubkeyHex)
onStartPrivateChat(convKey)
Log.d(TAG, "🗨️ Started geohash DM with $pubkeyHex -> $convKey")
}
fun getNostrKeyMapping(): Map<String, String> = repo.getNostrKeyMapping()
fun blockUserInGeohash(targetNickname: String) {
val pubkey = repo.findPubkeyByNickname(targetNickname)
if (pubkey != null) {
dataManager.addGeohashBlockedUser(pubkey)
val sysMsg = com.bitchat.android.model.BitchatMessage(
sender = "system",
content = "blocked $targetNickname in geohash channels",
timestamp = Date(),
isRelay = false
)
fun startGeohashDM(pubkeyHex: String, onStartPrivateChat: (String) -> Unit) {
val convKey = "nostr_${pubkeyHex.take(16)}"
repo.putNostrKeyMapping(convKey, pubkeyHex)
@@ -174,6 +170,21 @@ class GeohashViewModel(
Log.d(TAG, "🗨️ Started geohash DM with ${pubkeyHex} -> ${convKey} (geohash=${gh})")
}
fun getNostrKeyMapping(): Map<String, String> = repo.getNostrKeyMapping()
fun blockUserInGeohash(targetNickname: String) {
val pubkey = repo.findPubkeyByNickname(targetNickname)
if (pubkey != null) {
dataManager.addGeohashBlockedUser(pubkey)
// Refresh people list and counts to remove blocked entry immediately
repo.refreshGeohashPeople()
repo.updateReactiveParticipantCounts()
val sysMsg = com.bitchat.android.model.BitchatMessage(
sender = "system",
content = "blocked $targetNickname in geohash channels",
timestamp = Date(),
isRelay = false
)
messageManager.addMessage(sysMsg)
} else {
val sysMsg = com.bitchat.android.model.BitchatMessage(