mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-24 23:45:19 +00:00
wip: nickname disambiguation
This commit is contained in:
@@ -636,6 +636,10 @@ class BluetoothMeshService(private val context: Context) {
|
||||
if (connectionManager.startServices()) {
|
||||
isActive = true
|
||||
|
||||
// Add ourselves to peer manager for collision detection
|
||||
val myNickname = try { com.bitchat.android.services.NicknameProvider.getNickname(context, myPeerID) } catch (_: Exception) { myPeerID }
|
||||
peerManager.addOrUpdatePeer(myPeerID, myNickname)
|
||||
|
||||
// Start periodic announcements for peer discovery and connectivity
|
||||
sendPeriodicBroadcastAnnounce()
|
||||
Log.d(TAG, "Started periodic broadcast announcements (every 30 seconds)")
|
||||
@@ -697,6 +701,14 @@ class BluetoothMeshService(private val context: Context) {
|
||||
return reusable
|
||||
}
|
||||
|
||||
/**
|
||||
* Update our own nickname in peer manager and announce it
|
||||
*/
|
||||
fun updateSelfNickname(newNickname: String) {
|
||||
peerManager.addOrUpdatePeer(myPeerID, newNickname)
|
||||
sendBroadcastAnnounce()
|
||||
}
|
||||
|
||||
/**
|
||||
* Send public message
|
||||
*/
|
||||
@@ -1176,6 +1188,11 @@ class BluetoothMeshService(private val context: Context) {
|
||||
*/
|
||||
fun getPeerNicknames(): Map<String, String> = peerManager.getAllPeerNicknames()
|
||||
|
||||
/**
|
||||
* Get disambiguated peer nickname (nickname#suffix if collisions exist)
|
||||
*/
|
||||
fun getDisambiguatedNickname(peerID: String): String = peerManager.getDisambiguatedNickname(peerID)
|
||||
|
||||
/**
|
||||
* Get peer RSSI values
|
||||
*/
|
||||
|
||||
@@ -207,22 +207,7 @@ class PeerManager {
|
||||
fun addOrUpdatePeer(peerID: String, nickname: String): Boolean {
|
||||
if (peerID == "unknown") return false
|
||||
|
||||
// Clean up stale peer IDs with the same nickname (exact same logic as iOS)
|
||||
val now = System.currentTimeMillis()
|
||||
val stalePeerIDs = mutableListOf<String>()
|
||||
peers.forEach { (existingPeerID, info) ->
|
||||
if (info.nickname == nickname && existingPeerID != peerID) {
|
||||
val wasRecentlySeen = (now - info.lastSeen) < 10000
|
||||
if (!wasRecentlySeen) {
|
||||
stalePeerIDs.add(existingPeerID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove stale peer IDs
|
||||
stalePeerIDs.forEach { stalePeerID ->
|
||||
removePeer(stalePeerID, notifyDelegate = false)
|
||||
}
|
||||
|
||||
// Check if this is a new peer announcement
|
||||
val isFirstAnnounce = !announcedPeers.contains(peerID)
|
||||
@@ -313,6 +298,16 @@ class PeerManager {
|
||||
return peers[peerID]?.nickname
|
||||
}
|
||||
|
||||
/**
|
||||
* Get disambiguated peer nickname (nickname#suffix if collisions exist)
|
||||
*/
|
||||
fun getDisambiguatedNickname(peerID: String): String {
|
||||
val info = peers[peerID] ?: return peerID
|
||||
val nick = info.nickname.trim()
|
||||
val isAmbiguous = peers.values.count { it.nickname.trim().equals(nick, ignoreCase = true) } > 1
|
||||
return if (isAmbiguous) "$nick#${peerID.takeLast(4)}" else nick
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all peer nicknames
|
||||
*/
|
||||
|
||||
@@ -37,10 +37,25 @@ class GeohashRepository(
|
||||
fun getConversationGeohash(convKey: String): String? = conversationGeohash[convKey]
|
||||
|
||||
fun findPubkeyByNickname(targetNickname: String): String? {
|
||||
return geoNicknames.entries.firstOrNull { (_, nickname) ->
|
||||
val base = nickname.split("#").firstOrNull() ?: nickname
|
||||
base == targetNickname
|
||||
val parts = targetNickname.split("#")
|
||||
val baseName = parts[0]
|
||||
val suffix = if (parts.size > 1) parts[1] else null
|
||||
|
||||
if (suffix != null) {
|
||||
// Exact match attempt: nickname + pubkey suffix
|
||||
return geoNicknames.entries.find { (id, nick) ->
|
||||
val base = nick.split("#").firstOrNull() ?: nick
|
||||
base.equals(baseName, ignoreCase = true) && id.endsWith(suffix, ignoreCase = true)
|
||||
}?.key
|
||||
} else {
|
||||
// No suffix provided. Check for matches.
|
||||
val matches = geoNicknames.entries.filter { (_, nick) ->
|
||||
val base = nick.split("#").firstOrNull() ?: nick
|
||||
base.equals(baseName, ignoreCase = true)
|
||||
}
|
||||
// If only one match, return it. If multiple, it's ambiguous (return null or handle)
|
||||
return if (matches.size == 1) matches.first().key else null
|
||||
}
|
||||
}
|
||||
|
||||
// peerID alias -> nostr pubkey mapping for geohash DMs and temp aliases
|
||||
|
||||
@@ -167,9 +167,13 @@ fun ChatScreen(viewModel: ChatViewModel) {
|
||||
},
|
||||
onMessageLongPress = { message ->
|
||||
// Message long press - open user action sheet with message context
|
||||
// Extract base nickname from message sender (contains all necessary info)
|
||||
val (baseName, _) = splitSuffix(message.sender)
|
||||
selectedUserForSheet = baseName
|
||||
// Use disambiguated name so actions like /block work with suffixes if collisions exist
|
||||
val disambiguated = if (message.senderPeerID != null && !message.senderPeerID.startsWith("nostr_")) {
|
||||
viewModel.meshService.getDisambiguatedNickname(message.senderPeerID)
|
||||
} else {
|
||||
message.sender
|
||||
}
|
||||
selectedUserForSheet = disambiguated
|
||||
selectedMessageForSheet = message
|
||||
showUserSheet = true
|
||||
},
|
||||
|
||||
@@ -53,8 +53,21 @@ fun formatMessageAsAnnotatedString(
|
||||
val isSelf = message.senderPeerID == meshService.myPeerID ||
|
||||
message.sender == currentUserNickname ||
|
||||
message.sender.startsWith("$currentUserNickname#")
|
||||
|
||||
if (message.sender != "system") {
|
||||
// Resolve disambiguated sender name if it's a mesh message
|
||||
val senderDisplayName = if (message.senderPeerID != null && !message.senderPeerID.startsWith("nostr_")) {
|
||||
val disambiguated = meshService.getDisambiguatedNickname(message.senderPeerID)
|
||||
// If it returned the raw peerID because the peer is offline, fall back to message.sender (nickname at time of send)
|
||||
if (disambiguated == message.senderPeerID && message.sender != message.senderPeerID) {
|
||||
message.sender
|
||||
} else {
|
||||
disambiguated
|
||||
}
|
||||
} else {
|
||||
message.sender
|
||||
}
|
||||
|
||||
|
||||
// Get base color for this peer (iOS-style color assignment)
|
||||
val baseColor = if (isSelf) {
|
||||
Color(0xFFFF9500) // Orange for self (iOS orange)
|
||||
@@ -63,7 +76,7 @@ fun formatMessageAsAnnotatedString(
|
||||
}
|
||||
|
||||
// Split sender into base name and hashtag suffix
|
||||
val (baseName, suffix) = splitSuffix(message.sender)
|
||||
val (baseName, suffix) = splitSuffix(senderDisplayName)
|
||||
|
||||
// Sender prefix "<@"
|
||||
builder.pushStyle(SpanStyle(
|
||||
@@ -85,11 +98,11 @@ fun formatMessageAsAnnotatedString(
|
||||
builder.append(truncatedBase)
|
||||
val nicknameEnd = builder.length
|
||||
|
||||
// Add click annotation for nickname (store canonical sender name with hash if available)
|
||||
// Add click annotation for nickname (store disambiguated name for mentions)
|
||||
if (!isSelf) {
|
||||
builder.addStringAnnotation(
|
||||
tag = "nickname_click",
|
||||
annotation = (message.originalSender ?: message.sender),
|
||||
annotation = senderDisplayName,
|
||||
start = nicknameStart,
|
||||
end = nicknameEnd
|
||||
)
|
||||
@@ -174,8 +187,21 @@ fun formatMessageHeaderAnnotatedString(
|
||||
message.sender.startsWith("$currentUserNickname#")
|
||||
|
||||
if (message.sender != "system") {
|
||||
// Resolve disambiguated sender name if it's a mesh message
|
||||
val senderDisplayName = if (message.senderPeerID != null && !message.senderPeerID.startsWith("nostr_")) {
|
||||
val disambiguated = meshService.getDisambiguatedNickname(message.senderPeerID)
|
||||
// If it returned the raw peerID because the peer is offline, fall back to message.sender (nickname at time of send)
|
||||
if (disambiguated == message.senderPeerID && message.sender != message.senderPeerID) {
|
||||
message.sender
|
||||
} else {
|
||||
disambiguated
|
||||
}
|
||||
} else {
|
||||
message.sender
|
||||
}
|
||||
|
||||
val baseColor = if (isSelf) Color(0xFFFF9500) else getPeerColor(message, isDark)
|
||||
val (baseName, suffix) = splitSuffix(message.sender)
|
||||
val (baseName, suffix) = splitSuffix(senderDisplayName)
|
||||
|
||||
// "<@"
|
||||
builder.pushStyle(SpanStyle(
|
||||
@@ -198,7 +224,7 @@ fun formatMessageHeaderAnnotatedString(
|
||||
if (!isSelf) {
|
||||
builder.addStringAnnotation(
|
||||
tag = "nickname_click",
|
||||
annotation = (message.originalSender ?: message.sender),
|
||||
annotation = senderDisplayName,
|
||||
start = nicknameStart,
|
||||
end = nicknameEnd
|
||||
)
|
||||
|
||||
@@ -317,7 +317,7 @@ class ChatViewModel(
|
||||
fun setNickname(newNickname: String) {
|
||||
state.setNickname(newNickname)
|
||||
dataManager.saveNickname(newNickname)
|
||||
meshService.sendBroadcastAnnounce()
|
||||
meshService.updateSelfNickname(newNickname)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,7 +519,7 @@ class ChatViewModel(
|
||||
}
|
||||
}
|
||||
// Send private message
|
||||
val recipientNickname = meshService.getPeerNicknames()[selectedPeer]
|
||||
val recipientNickname = meshService.getDisambiguatedNickname(selectedPeer)
|
||||
privateChatManager.sendPrivateMessage(
|
||||
content,
|
||||
selectedPeer,
|
||||
@@ -581,10 +581,6 @@ class ChatViewModel(
|
||||
|
||||
// MARK: - Utility Functions
|
||||
|
||||
fun getPeerIDForNickname(nickname: String): String? {
|
||||
return meshService.getPeerNicknames().entries.find { it.value == nickname }?.key
|
||||
}
|
||||
|
||||
fun toggleFavorite(peerID: String) {
|
||||
Log.d("ChatViewModel", "toggleFavorite called for peerID: $peerID")
|
||||
privateChatManager.toggleFavorite(peerID)
|
||||
|
||||
@@ -80,9 +80,11 @@ class CommandProcessor(
|
||||
private fun handleMessageCommand(parts: List<String>, meshService: BluetoothMeshService) {
|
||||
if (parts.size > 1) {
|
||||
val targetName = parts[1].removePrefix("@")
|
||||
val peerID = getPeerIDForNickname(targetName, meshService)
|
||||
val resolution = resolvePeerIDForNickname(targetName, meshService)
|
||||
|
||||
if (peerID != null) {
|
||||
when (resolution) {
|
||||
is PeerResolutionResult.Found -> {
|
||||
val peerID = resolution.peerID
|
||||
val success = privateChatManager.startPrivateChat(peerID, meshService)
|
||||
|
||||
if (success) {
|
||||
@@ -109,7 +111,17 @@ class CommandProcessor(
|
||||
messageManager.addMessage(systemMessage)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
is PeerResolutionResult.Ambiguous -> {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "multiple users found with nickname '$targetName'. please use one of: ${resolution.candidates.joinToString(", ")}",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
}
|
||||
is PeerResolutionResult.NotFound -> {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "user '$targetName' not found. they may be offline or using a different nickname.",
|
||||
@@ -118,6 +130,7 @@ class CommandProcessor(
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
@@ -251,7 +264,31 @@ class CommandProcessor(
|
||||
private fun handleBlockCommand(parts: List<String>, meshService: BluetoothMeshService) {
|
||||
if (parts.size > 1) {
|
||||
val targetName = parts[1].removePrefix("@")
|
||||
privateChatManager.blockPeerByNickname(targetName, meshService)
|
||||
val resolution = resolvePeerIDForNickname(targetName, meshService)
|
||||
|
||||
when (resolution) {
|
||||
is PeerResolutionResult.Found -> {
|
||||
privateChatManager.blockPeer(resolution.peerID, meshService)
|
||||
}
|
||||
is PeerResolutionResult.Ambiguous -> {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "multiple users found with nickname '$targetName'. please use one of: ${resolution.candidates.joinToString(", ")}",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
}
|
||||
is PeerResolutionResult.NotFound -> {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "user '$targetName' not found.",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// List blocked users
|
||||
val blockedInfo = privateChatManager.listBlockedUsers()
|
||||
@@ -268,7 +305,31 @@ class CommandProcessor(
|
||||
private fun handleUnblockCommand(parts: List<String>, meshService: BluetoothMeshService) {
|
||||
if (parts.size > 1) {
|
||||
val targetName = parts[1].removePrefix("@")
|
||||
privateChatManager.unblockPeerByNickname(targetName, meshService)
|
||||
val resolution = resolvePeerIDForNickname(targetName, meshService)
|
||||
|
||||
when (resolution) {
|
||||
is PeerResolutionResult.Found -> {
|
||||
privateChatManager.unblockPeer(resolution.peerID, meshService)
|
||||
}
|
||||
is PeerResolutionResult.Ambiguous -> {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "multiple users found with nickname '$targetName'. please use one of: ${resolution.candidates.joinToString(", ")}",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
}
|
||||
is PeerResolutionResult.NotFound -> {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "user '$targetName' not found.",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
@@ -448,7 +509,12 @@ class CommandProcessor(
|
||||
is com.bitchat.android.geohash.ChannelID.Mesh,
|
||||
null -> {
|
||||
// Mesh channel: use Bluetooth mesh peer nicknames
|
||||
meshService.getPeerNicknames().values.filter { it != meshService.getPeerNicknames()[meshService.myPeerID] }
|
||||
val nicknames = meshService.getPeerNicknames().toMap() // Take a stable snapshot
|
||||
val myPeerID = meshService.myPeerID
|
||||
nicknames.filter { it.key != myPeerID }.map { (id, nick) ->
|
||||
val isAmbiguous = nicknames.values.count { it == nick } > 1
|
||||
if (isAmbiguous) "$nick#${id.takeLast(4)}" else nick
|
||||
}
|
||||
}
|
||||
|
||||
is com.bitchat.android.geohash.ChannelID.Location -> {
|
||||
@@ -503,12 +569,39 @@ class CommandProcessor(
|
||||
|
||||
// MARK: - Utility Functions
|
||||
|
||||
private fun getPeerIDForNickname(nickname: String, meshService: BluetoothMeshService): String? {
|
||||
return meshService.getPeerNicknames().entries.find { it.value == nickname }?.key
|
||||
private sealed class PeerResolutionResult {
|
||||
data class Found(val peerID: String) : PeerResolutionResult()
|
||||
object NotFound : PeerResolutionResult()
|
||||
data class Ambiguous(val candidates: List<String>) : PeerResolutionResult()
|
||||
}
|
||||
|
||||
private fun resolvePeerIDForNickname(targetName: String, meshService: BluetoothMeshService): PeerResolutionResult {
|
||||
val nicknames = meshService.getPeerNicknames()
|
||||
|
||||
val parts = targetName.split("#")
|
||||
val baseName = parts[0]
|
||||
val suffix = if (parts.size > 1) parts[1] else null
|
||||
|
||||
if (suffix != null) {
|
||||
val peerID = nicknames.entries.find { (id, nick) ->
|
||||
nick.equals(baseName, ignoreCase = true) && id.takeLast(4).equals(suffix, ignoreCase = true)
|
||||
}?.key
|
||||
return if (peerID != null) PeerResolutionResult.Found(peerID) else PeerResolutionResult.NotFound
|
||||
} else {
|
||||
val matches = nicknames.entries.filter { it.value.equals(baseName, ignoreCase = true) }
|
||||
return when {
|
||||
matches.isEmpty() -> PeerResolutionResult.NotFound
|
||||
matches.size == 1 -> PeerResolutionResult.Found(matches.first().key)
|
||||
else -> {
|
||||
val candidates = matches.map { "${it.value}#${it.key.takeLast(4)}" }
|
||||
PeerResolutionResult.Ambiguous(candidates)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPeerNickname(peerID: String, meshService: BluetoothMeshService): String {
|
||||
return meshService.getPeerNicknames()[peerID] ?: peerID
|
||||
return meshService.getDisambiguatedNickname(peerID)
|
||||
}
|
||||
|
||||
private fun getMyPeerID(meshService: BluetoothMeshService): String {
|
||||
|
||||
@@ -54,8 +54,8 @@ class MeshDelegateHandler(
|
||||
|
||||
// Show notification with enhanced information - now includes senderPeerID
|
||||
message.senderPeerID?.let { senderPeerID ->
|
||||
// Use nickname if available, fall back to sender or senderPeerID
|
||||
val senderNickname = message.sender.takeIf { it != senderPeerID } ?: senderPeerID
|
||||
// Use disambiguated nickname for notifications
|
||||
val senderNickname = getMeshService().getDisambiguatedNickname(senderPeerID)
|
||||
val preview = NotificationTextUtils.buildPrivateMessagePreview(message)
|
||||
notificationManager.showPrivateMessageNotification(
|
||||
senderPeerID = senderPeerID,
|
||||
@@ -250,10 +250,11 @@ class MeshDelegateHandler(
|
||||
val isMention = checkForMeshMention(message.content, currentNickname)
|
||||
|
||||
if (isMention) {
|
||||
android.util.Log.d("MeshDelegateHandler", "🔔 Triggering mesh mention notification from ${message.sender}")
|
||||
val senderNickname = message.senderPeerID?.let { getMeshService().getDisambiguatedNickname(it) } ?: message.sender
|
||||
android.util.Log.d("MeshDelegateHandler", "🔔 Triggering mesh mention notification from $senderNickname")
|
||||
|
||||
notificationManager.showMeshMentionNotification(
|
||||
senderNickname = message.sender,
|
||||
senderNickname = senderNickname,
|
||||
messageContent = message.content,
|
||||
senderPeerID = message.senderPeerID
|
||||
)
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.bitchat.android.geohash.ChannelID
|
||||
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
|
||||
import com.bitchat.android.nostr.GeohashAliasRegistry
|
||||
import com.bitchat.android.nostr.GeohashConversationRegistry
|
||||
import com.bitchat.android.util.toHexString
|
||||
|
||||
|
||||
/**
|
||||
@@ -367,7 +368,7 @@ fun PeopleSection(
|
||||
// Offline favorites (exclude ones mapped to connected)
|
||||
val offlineFavorites = com.bitchat.android.favorites.FavoritesPersistenceService.shared.getOurFavorites()
|
||||
offlineFavorites.forEach { fav ->
|
||||
val favPeerID = fav.peerNoisePublicKey.joinToString("") { b -> "%02x".format(b) }
|
||||
val favPeerID = fav.peerNoisePublicKey.toHexString()
|
||||
val isMappedToConnected = noiseHexByPeerID.values.any { it.equals(favPeerID, ignoreCase = true) }
|
||||
if (!isMappedToConnected) {
|
||||
val dn = peerNicknames[favPeerID] ?: fav.peerNickname
|
||||
@@ -435,7 +436,7 @@ fun PeopleSection(
|
||||
|
||||
// Append offline favorites we actively favorite (and not currently connected)
|
||||
offlineFavorites.forEach { fav ->
|
||||
val favPeerID = fav.peerNoisePublicKey.joinToString("") { b -> "%02x".format(b) }
|
||||
val favPeerID = fav.peerNoisePublicKey.toHexString()
|
||||
// If any connected peer maps to this noise key, skip showing the offline entry
|
||||
val isMappedToConnected = noiseHexByPeerID.values.any { it.equals(favPeerID, ignoreCase = true) }
|
||||
if (isMappedToConnected) return@forEach
|
||||
@@ -560,7 +561,7 @@ private fun PeerItem(
|
||||
// Split display name for hashtag suffix support (iOS-compatible)
|
||||
val (baseNameRaw, suffixRaw) = splitSuffix(displayName)
|
||||
val baseName = truncateNickname(baseNameRaw)
|
||||
val suffix = if (showHashSuffix) suffixRaw else ""
|
||||
val suffix = if (showHashSuffix && suffixRaw.isEmpty()) "#${peerID.takeLast(4)}" else if (showHashSuffix) suffixRaw else ""
|
||||
val isMe = displayName == "You" || peerID == currentNickname
|
||||
|
||||
// Get consistent peer color (iOS-compatible)
|
||||
|
||||
@@ -193,7 +193,7 @@ class PrivateChatManager(
|
||||
if (fingerprint != null) {
|
||||
dataManager.addBlockedUser(fingerprint)
|
||||
|
||||
val peerNickname = getPeerNickname(peerID, meshService)
|
||||
val peerNickname = meshService.getDisambiguatedNickname(peerID)
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "blocked user $peerNickname",
|
||||
@@ -217,7 +217,7 @@ class PrivateChatManager(
|
||||
if (fingerprint != null && dataManager.isUserBlocked(fingerprint)) {
|
||||
dataManager.removeBlockedUser(fingerprint)
|
||||
|
||||
val peerNickname = getPeerNickname(peerID, meshService)
|
||||
val peerNickname = meshService.getDisambiguatedNickname(peerID)
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "unblocked user $peerNickname",
|
||||
@@ -230,52 +230,6 @@ class PrivateChatManager(
|
||||
return false
|
||||
}
|
||||
|
||||
fun blockPeerByNickname(targetName: String, meshService: BluetoothMeshService): Boolean {
|
||||
val peerID = getPeerIDForNickname(targetName, meshService)
|
||||
|
||||
if (peerID != null) {
|
||||
return blockPeer(peerID, meshService)
|
||||
} else {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "user '$targetName' not found",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun unblockPeerByNickname(targetName: String, meshService: BluetoothMeshService): Boolean {
|
||||
val peerID = getPeerIDForNickname(targetName, meshService)
|
||||
|
||||
if (peerID != null) {
|
||||
val fingerprint = fingerprintManager.getFingerprintForPeer(peerID)
|
||||
if (fingerprint != null && dataManager.isUserBlocked(fingerprint)) {
|
||||
return unblockPeer(peerID, meshService)
|
||||
} else {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "user '$targetName' is not blocked",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
val systemMessage = BitchatMessage(
|
||||
sender = "system",
|
||||
content = "user '$targetName' not found",
|
||||
timestamp = Date(),
|
||||
isRelay = false
|
||||
)
|
||||
messageManager.addMessage(systemMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun listBlockedUsers(): String {
|
||||
val blockedCount = dataManager.blockedUsers.size
|
||||
return if (blockedCount == 0) {
|
||||
@@ -413,12 +367,8 @@ class PrivateChatManager(
|
||||
|
||||
// MARK: - Utility Functions
|
||||
|
||||
private fun getPeerIDForNickname(nickname: String, meshService: BluetoothMeshService): String? {
|
||||
return meshService.getPeerNicknames().entries.find { it.value == nickname }?.key
|
||||
}
|
||||
|
||||
private fun getPeerNickname(peerID: String, meshService: BluetoothMeshService): String {
|
||||
return meshService.getPeerNicknames()[peerID] ?: peerID
|
||||
return meshService.getDisambiguatedNickname(peerID)
|
||||
}
|
||||
|
||||
// MARK: - Consolidation
|
||||
|
||||
Reference in New Issue
Block a user