mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 03:05:20 +00:00
nostr: fix block feature (#427)
* fix block feature * fix nostr nickname in sidebar
This commit is contained in:
@@ -22,7 +22,8 @@ class GeohashMessageHandler(
|
|||||||
private val state: ChatState,
|
private val state: ChatState,
|
||||||
private val messageManager: MessageManager,
|
private val messageManager: MessageManager,
|
||||||
private val repo: GeohashRepository,
|
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" }
|
companion object { private const val TAG = "GeohashMessageHandler" }
|
||||||
|
|
||||||
@@ -56,8 +57,8 @@ class GeohashMessageHandler(
|
|||||||
if (!NostrProofOfWork.validateDifficulty(event, pow.difficulty)) return@launch
|
if (!NostrProofOfWork.validateDifficulty(event, pow.difficulty)) return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocked users check
|
// Blocked users check (use injected DataManager which has loaded state)
|
||||||
if (com.bitchat.android.ui.DataManager(application).isGeohashUserBlocked(event.pubkey)) return@launch
|
if (dataManager.isGeohashUserBlocked(event.pubkey)) return@launch
|
||||||
|
|
||||||
// Update repository (participants, nickname, teleport)
|
// Update repository (participants, nickname, teleport)
|
||||||
// Update repository on a background-safe path; repository will post updates to LiveData
|
// Update repository on a background-safe path; repository will post updates to LiveData
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import java.util.Date
|
|||||||
*/
|
*/
|
||||||
class GeohashRepository(
|
class GeohashRepository(
|
||||||
private val application: Application,
|
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" }
|
companion object { private const val TAG = "GeohashRepository" }
|
||||||
|
|
||||||
@@ -103,7 +104,8 @@ class GeohashRepository(
|
|||||||
val e = it.next()
|
val e = it.next()
|
||||||
if (e.value.before(cutoff)) it.remove()
|
if (e.value.before(cutoff)) it.remove()
|
||||||
}
|
}
|
||||||
return participants.size
|
// exclude blocked users
|
||||||
|
return participants.keys.count { !dataManager.isGeohashUserBlocked(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshGeohashPeople() {
|
fun refreshGeohashPeople() {
|
||||||
@@ -122,8 +124,18 @@ class GeohashRepository(
|
|||||||
if (e.value.before(cutoff)) it.remove()
|
if (e.value.before(cutoff)) it.remove()
|
||||||
}
|
}
|
||||||
geohashParticipants[geohash] = participants
|
geohashParticipants[geohash] = participants
|
||||||
val people = participants.map { (pubkeyHex, lastSeen) ->
|
// exclude blocked users from people list
|
||||||
val base = getCachedNickname(pubkeyHex) ?: "anon"
|
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(
|
GeoPerson(
|
||||||
id = pubkeyHex.lowercase(),
|
id = pubkeyHex.lowercase(),
|
||||||
displayName = base, // UI can add #hash if necessary
|
displayName = base, // UI can add #hash if necessary
|
||||||
@@ -138,7 +150,8 @@ class GeohashRepository(
|
|||||||
val cutoff = Date(System.currentTimeMillis() - 5 * 60 * 1000)
|
val cutoff = Date(System.currentTimeMillis() - 5 * 60 * 1000)
|
||||||
val counts = mutableMapOf<String, Int>()
|
val counts = mutableMapOf<String, Int>()
|
||||||
for ((gh, participants) in geohashParticipants) {
|
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
|
counts[gh] = active
|
||||||
}
|
}
|
||||||
// Use postValue for thread safety - this can be called from background threads
|
// Use postValue for thread safety - this can be called from background threads
|
||||||
@@ -186,6 +199,7 @@ class GeohashRepository(
|
|||||||
val participants = geohashParticipants[current] ?: emptyMap()
|
val participants = geohashParticipants[current] ?: emptyMap()
|
||||||
var count = 0
|
var count = 0
|
||||||
for ((k, t) in participants) {
|
for ((k, t) in participants) {
|
||||||
|
if (dataManager.isGeohashUserBlocked(k)) continue
|
||||||
if (t.before(cutoff)) continue
|
if (t.before(cutoff)) continue
|
||||||
val name = if (k.equals(lower, true)) base else (geoNicknames[k.lowercase()] ?: "anon")
|
val name = if (k.equals(lower, true)) base else (geoNicknames[k.lowercase()] ?: "anon")
|
||||||
if (name.equals(base, true)) { count++; if (count > 1) break }
|
if (name.equals(base, true)) { count++; if (count > 1) break }
|
||||||
@@ -207,6 +221,7 @@ class GeohashRepository(
|
|||||||
val participants = geohashParticipants[sourceGeohash] ?: emptyMap()
|
val participants = geohashParticipants[sourceGeohash] ?: emptyMap()
|
||||||
var count = 0
|
var count = 0
|
||||||
for ((k, t) in participants) {
|
for ((k, t) in participants) {
|
||||||
|
if (dataManager.isGeohashUserBlocked(k)) continue
|
||||||
if (t.before(cutoff)) continue
|
if (t.before(cutoff)) continue
|
||||||
val name = if (k.equals(lower, true)) base else (geoNicknames[k.lowercase()] ?: "anon")
|
val name = if (k.equals(lower, true)) base else (geoNicknames[k.lowercase()] ?: "anon")
|
||||||
if (name.equals(base, true)) { count++; if (count > 1) break }
|
if (name.equals(base, true)) { count++; if (count > 1) break }
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ class NostrDirectMessageHandler(
|
|||||||
private val privateChatManager: PrivateChatManager,
|
private val privateChatManager: PrivateChatManager,
|
||||||
private val meshDelegateHandler: MeshDelegateHandler,
|
private val meshDelegateHandler: MeshDelegateHandler,
|
||||||
private val scope: CoroutineScope,
|
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" }
|
companion object { private const val TAG = "NostrDirectMessageHandler" }
|
||||||
|
|
||||||
@@ -58,6 +59,10 @@ class NostrDirectMessageHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val (content, senderPubkey, rumorTimestamp) = decryptResult
|
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
|
if (!content.startsWith("bitchat1:")) return@launch
|
||||||
|
|
||||||
val base64Content = content.removePrefix("bitchat1:")
|
val base64Content = content.removePrefix("bitchat1:")
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ fun AboutSheet(
|
|||||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text("Tor On", fontFamily = FontFamily.Monospace)
|
Text("tor on", fontFamily = FontFamily.Monospace)
|
||||||
val statusColor = when {
|
val statusColor = when {
|
||||||
torStatus.running && torStatus.bootstrapPercent < 100 -> Color(0xFFFF9500)
|
torStatus.running && torStatus.bootstrapPercent < 100 -> Color(0xFFFF9500)
|
||||||
torStatus.running && torStatus.bootstrapPercent >= 100 -> if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D)
|
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" }
|
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 subscriptionManager = NostrSubscriptionManager(application, viewModelScope)
|
||||||
private val geohashMessageHandler = GeohashMessageHandler(application, state, messageManager, repo, viewModelScope)
|
private val geohashMessageHandler = GeohashMessageHandler(
|
||||||
private val dmHandler = NostrDirectMessageHandler(application, state, privateChatManager, meshDelegateHandler, viewModelScope, repo)
|
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 currentGeohashSubId: String? = null
|
||||||
private var currentDmSubId: String? = null
|
private var currentDmSubId: String? = null
|
||||||
@@ -141,25 +156,6 @@ class GeohashViewModel(
|
|||||||
fun geohashParticipantCount(geohash: String): Int = repo.geohashParticipantCount(geohash)
|
fun geohashParticipantCount(geohash: String): Int = repo.geohashParticipantCount(geohash)
|
||||||
fun isPersonTeleported(pubkeyHex: String): Boolean = repo.isPersonTeleported(pubkeyHex)
|
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) {
|
fun startGeohashDM(pubkeyHex: String, onStartPrivateChat: (String) -> Unit) {
|
||||||
val convKey = "nostr_${pubkeyHex.take(16)}"
|
val convKey = "nostr_${pubkeyHex.take(16)}"
|
||||||
repo.putNostrKeyMapping(convKey, pubkeyHex)
|
repo.putNostrKeyMapping(convKey, pubkeyHex)
|
||||||
@@ -174,6 +170,21 @@ class GeohashViewModel(
|
|||||||
Log.d(TAG, "🗨️ Started geohash DM with ${pubkeyHex} -> ${convKey} (geohash=${gh})")
|
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)
|
messageManager.addMessage(sysMsg)
|
||||||
} else {
|
} else {
|
||||||
val sysMsg = com.bitchat.android.model.BitchatMessage(
|
val sysMsg = com.bitchat.android.model.BitchatMessage(
|
||||||
|
|||||||
Reference in New Issue
Block a user