mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 08:05:22 +00:00
Geohash notifications (#288)
* mention notifications * notifications * warning
This commit is contained in:
@@ -29,7 +29,8 @@ class NostrGeohashService(
|
||||
private val privateChatManager: PrivateChatManager,
|
||||
private val meshDelegateHandler: MeshDelegateHandler,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val dataManager: com.bitchat.android.ui.DataManager
|
||||
private val dataManager: com.bitchat.android.ui.DataManager,
|
||||
private val notificationManager: com.bitchat.android.ui.NotificationManager
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -51,7 +52,8 @@ class NostrGeohashService(
|
||||
privateChatManager: PrivateChatManager,
|
||||
meshDelegateHandler: MeshDelegateHandler,
|
||||
coroutineScope: CoroutineScope,
|
||||
dataManager: com.bitchat.android.ui.DataManager
|
||||
dataManager: com.bitchat.android.ui.DataManager,
|
||||
notificationManager: com.bitchat.android.ui.NotificationManager
|
||||
): NostrGeohashService {
|
||||
return synchronized(this) {
|
||||
INSTANCE ?: NostrGeohashService(
|
||||
@@ -61,7 +63,8 @@ class NostrGeohashService(
|
||||
privateChatManager,
|
||||
meshDelegateHandler,
|
||||
coroutineScope,
|
||||
dataManager
|
||||
dataManager,
|
||||
notificationManager
|
||||
).also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
@@ -751,6 +754,10 @@ class NostrGeohashService(
|
||||
Log.d(TAG, "📡 Switched to mesh channel")
|
||||
// Immediate UI state updates
|
||||
currentGeohash = null
|
||||
// Update notification manager with current geohash
|
||||
notificationManager.setCurrentGeohash(null)
|
||||
// Clear mesh mention notifications since user is now viewing mesh chat
|
||||
notificationManager.clearMeshMentionNotifications()
|
||||
// Note: Don't clear geoNicknames - keep cached for when we return to location channels
|
||||
stopGeoParticipantsTimer()
|
||||
state.setGeohashPeople(emptyList())
|
||||
@@ -760,6 +767,10 @@ class NostrGeohashService(
|
||||
is com.bitchat.android.geohash.ChannelID.Location -> {
|
||||
Log.d(TAG, "📍 Switching to geohash channel: ${channel.channel.geohash}")
|
||||
currentGeohash = channel.channel.geohash
|
||||
// Update notification manager with current geohash
|
||||
notificationManager.setCurrentGeohash(channel.channel.geohash)
|
||||
// Clear notifications for this geohash since user is now viewing it
|
||||
notificationManager.clearNotificationsForGeohash(channel.channel.geohash)
|
||||
// Note: Don't clear geoNicknames - they contain cached nicknames for all geohashes
|
||||
|
||||
// Load stored messages for this geohash immediately
|
||||
@@ -1023,6 +1034,9 @@ class NostrGeohashService(
|
||||
messageManager.addMessage(message)
|
||||
}
|
||||
|
||||
// NOTIFICATION LOGIC: Check for mentions and first messages
|
||||
checkAndTriggerGeohashNotifications(geohash, senderName, content, message)
|
||||
|
||||
Log.d(TAG, "📥 Unified geohash event processed - geohash: $geohash, sender: $senderName, content: ${content.take(50)}")
|
||||
|
||||
} catch (e: Exception) {
|
||||
@@ -1030,6 +1044,104 @@ class NostrGeohashService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and trigger geohash notifications for mentions and first messages
|
||||
*/
|
||||
private fun checkAndTriggerGeohashNotifications(
|
||||
geohash: String,
|
||||
senderName: String,
|
||||
content: String,
|
||||
message: BitchatMessage
|
||||
) {
|
||||
try {
|
||||
// Get user's current nickname
|
||||
val currentNickname = state.getNicknameValue()
|
||||
if (currentNickname.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this message mentions the current user
|
||||
val isMention = checkForMention(content, currentNickname)
|
||||
|
||||
// Check if this is the first message in a subscribed geohash chat
|
||||
val isFirstMessage = checkIfFirstMessage(geohash, message)
|
||||
|
||||
// Only trigger notifications if we have a mention or first message
|
||||
if (isMention || isFirstMessage) {
|
||||
Log.d(TAG, "🔔 Triggering geohash notification - geohash: $geohash, mention: $isMention, first: $isFirstMessage")
|
||||
|
||||
notificationManager.showGeohashNotification(
|
||||
geohash = geohash,
|
||||
senderNickname = senderName,
|
||||
messageContent = content,
|
||||
isMention = isMention,
|
||||
isFirstMessage = isFirstMessage
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error checking geohash notifications: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the content mentions the current user with @nickname#hash format
|
||||
*/
|
||||
private fun checkForMention(content: String, currentNickname: String): Boolean {
|
||||
// iOS-style mention pattern: @nickname#1234 or @nickname
|
||||
val mentionPattern = "@([\\p{L}0-9_]+(?:#[a-fA-F0-9]{4})?)".toRegex()
|
||||
|
||||
return mentionPattern.findAll(content).any { match ->
|
||||
val mentionWithoutAt = match.groupValues[1]
|
||||
// Split the mention to get base nickname (without #hash suffix)
|
||||
val baseName = if (mentionWithoutAt.contains("#")) {
|
||||
mentionWithoutAt.substringBeforeLast("#")
|
||||
} else {
|
||||
mentionWithoutAt
|
||||
}
|
||||
|
||||
// Check if the base name matches current user's nickname
|
||||
baseName.equals(currentNickname, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is the first message in a subscribed geohash chat
|
||||
*/
|
||||
private fun checkIfFirstMessage(geohash: String, message: BitchatMessage): Boolean {
|
||||
// Get the message history for this geohash
|
||||
val messageHistory = geohashMessageHistory[geohash] ?: return true
|
||||
|
||||
// Filter out our own messages (local echoes and messages from our identity)
|
||||
val otherUserMessages = messageHistory.filter { msg ->
|
||||
// Check if this is our own message by comparing sender ID with our geohash identity
|
||||
try {
|
||||
val myGeoIdentity = NostrIdentityBridge.deriveIdentity(
|
||||
forGeohash = geohash,
|
||||
context = application
|
||||
)
|
||||
val myIdentityId = "nostr:${myGeoIdentity.publicKeyHex.take(8)}"
|
||||
msg.senderPeerID != myIdentityId && msg.senderPeerID != message.senderPeerID
|
||||
} catch (e: Exception) {
|
||||
// If we can't determine identity, assume it's not our message
|
||||
msg.senderPeerID != message.senderPeerID
|
||||
}
|
||||
}
|
||||
|
||||
// This is a first message if there are no other user messages and this isn't from us
|
||||
val isFromUs = try {
|
||||
val myGeoIdentity = NostrIdentityBridge.deriveIdentity(
|
||||
forGeohash = geohash,
|
||||
context = application
|
||||
)
|
||||
val myIdentityId = "nostr:${myGeoIdentity.publicKeyHex.take(8)}"
|
||||
message.senderPeerID == myIdentityId
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
return otherUserMessages.isEmpty() && !isFromUs
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle geohash DM event (private messages in geohash context) - iOS compatible
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user