Final touches.

This commit is contained in:
Vitor Pamplona
2026-03-19 17:07:03 -04:00
parent 856e85988a
commit 11b5ebe108
5 changed files with 74 additions and 33 deletions
@@ -210,7 +210,10 @@ class EventNotificationConsumer(
val content = chatNote.event?.content ?: "" val content = chatNote.event?.content ?: ""
val user = chatNote.author?.toBestDisplayName() ?: "" val user = chatNote.author?.toBestDisplayName() ?: ""
val userPicture = chatNote.author?.profilePicture() val userPicture = chatNote.author?.profilePicture()
val accountNpub = account.signer.pubKey.hexToByteArray().toNpub() val accountNpub =
account.signer.pubKey
.hexToByteArray()
.toNpub()
val chatroomMembers = chatRoom.users.joinToString(",") val chatroomMembers = chatRoom.users.joinToString(",")
val noteUri = chatNote.toNEvent() + ACCOUNT_QUERY_PARAM + accountNpub val noteUri = chatNote.toNEvent() + ACCOUNT_QUERY_PARAM + accountNpub
@@ -224,6 +227,7 @@ class EventNotificationConsumer(
noteUri, noteUri,
applicationContext, applicationContext,
accountNpub = accountNpub, accountNpub = accountNpub,
accountPictureUrl = account.userProfile().profilePicture(),
chatroomMembers = chatroomMembers, chatroomMembers = chatroomMembers,
) )
} }
@@ -254,20 +258,24 @@ class EventNotificationConsumer(
val content = chatNote.event?.content ?: "" val content = chatNote.event?.content ?: ""
val user = chatNote.author?.toBestDisplayName() ?: "" val user = chatNote.author?.toBestDisplayName() ?: ""
val userPicture = chatNote.author?.profilePicture() val userPicture = chatNote.author?.profilePicture()
val accountNpub = account.signer.pubKey.hexToByteArray().toNpub() val accountNpub =
account.signer.pubKey
.hexToByteArray()
.toNpub()
val chatroomMembers = chatRoom.users.joinToString(",") val chatroomMembers = chatRoom.users.joinToString(",")
val noteUri = chatNote.toNEvent() + ACCOUNT_QUERY_PARAM + accountNpub val noteUri = chatNote.toNEvent() + ACCOUNT_QUERY_PARAM + accountNpub
notificationManager() notificationManager()
.sendDMNotification( .sendDMNotification(
event.id, id = event.id,
content, messageBody = content,
user, senderName = user,
event.createdAt, time = event.createdAt,
userPicture, pictureUrl = userPicture,
noteUri, uri = noteUri,
applicationContext, applicationContext = applicationContext,
accountNpub = accountNpub, accountNpub = accountNpub,
accountPictureUrl = account.userProfile().profilePicture(),
chatroomMembers = chatroomMembers, chatroomMembers = chatroomMembers,
) )
} }
@@ -297,19 +305,23 @@ class EventNotificationConsumer(
decryptContent(note, account.signer)?.let { content -> decryptContent(note, account.signer)?.let { content ->
val user = note.author?.toBestDisplayName() ?: "" val user = note.author?.toBestDisplayName() ?: ""
val userPicture = note.author?.profilePicture() val userPicture = note.author?.profilePicture()
val accountNpub = account.signer.pubKey.hexToByteArray().toNpub() val accountNpub =
account.signer.pubKey
.hexToByteArray()
.toNpub()
val noteUri = note.toNEvent() + ACCOUNT_QUERY_PARAM + accountNpub val noteUri = note.toNEvent() + ACCOUNT_QUERY_PARAM + accountNpub
notificationManager() notificationManager()
.sendDMNotification( .sendDMNotification(
event.id, id = event.id,
content, messageBody = content,
user, senderName = user,
event.createdAt, time = event.createdAt,
userPicture, pictureUrl = userPicture,
noteUri, uri = noteUri,
applicationContext, applicationContext = applicationContext,
accountNpub = accountNpub, accountNpub = accountNpub,
accountPictureUrl = account.userProfile().profilePicture(),
chatroomMembers = null, chatroomMembers = null,
) )
} }
@@ -34,6 +34,7 @@ import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.coroutines.cancellation.CancellationException import kotlin.coroutines.cancellation.CancellationException
@@ -53,10 +54,13 @@ class NotificationReplyReceiver : BroadcastReceiver() {
NotificationUtils.MARK_READ_ACTION -> { NotificationUtils.MARK_READ_ACTION -> {
notificationManager.cancel(notificationId) notificationManager.cancel(notificationId)
} }
NotificationUtils.REPLY_ACTION -> { NotificationUtils.REPLY_ACTION -> {
val replyText = RemoteInput.getResultsFromIntent(intent) val replyText =
?.getCharSequence(NotificationUtils.KEY_REPLY_TEXT) RemoteInput
?.toString() .getResultsFromIntent(intent)
?.getCharSequence(NotificationUtils.KEY_REPLY_TEXT)
?.toString()
if (replyText.isNullOrBlank()) return if (replyText.isNullOrBlank()) return
@@ -69,6 +73,13 @@ class NotificationReplyReceiver : BroadcastReceiver() {
val pendingResult = goAsync() val pendingResult = goAsync()
scope.launch { scope.launch {
// activates the relay to send the message.
val collectionJob =
scope.launch {
Amethyst.instance.relayProxyClientConnector.relayServices
.collect()
}
try { try {
sendReply(accountNpub, members, replyText) sendReply(accountNpub, members, replyText)
notificationManager.cancel(notificationId) notificationManager.cancel(notificationId)
@@ -77,6 +88,9 @@ class NotificationReplyReceiver : BroadcastReceiver() {
Log.e("NotificationReply", "Failed to send reply: ${e.message}") Log.e("NotificationReply", "Failed to send reply: ${e.message}")
} finally { } finally {
pendingResult.finish() pendingResult.finish()
// closes the relay connection.
collectionJob.cancel()
} }
} }
} }
@@ -136,6 +136,7 @@ object NotificationUtils {
uri: String, uri: String,
applicationContext: Context, applicationContext: Context,
accountNpub: String? = null, accountNpub: String? = null,
accountPictureUrl: String? = null,
chatroomMembers: String? = null, chatroomMembers: String? = null,
) { ) {
getOrCreateDMChannel(applicationContext) getOrCreateDMChannel(applicationContext)
@@ -151,6 +152,7 @@ object NotificationUtils {
channelId = channelId, channelId = channelId,
applicationContext = applicationContext, applicationContext = applicationContext,
accountNpub = accountNpub, accountNpub = accountNpub,
accountPictureUrl = accountPictureUrl,
chatroomMembers = chatroomMembers, chatroomMembers = chatroomMembers,
) )
} }
@@ -180,6 +182,7 @@ object NotificationUtils {
channelId: String, channelId: String,
applicationContext: Context, applicationContext: Context,
accountNpub: String?, accountNpub: String?,
accountPictureUrl: String?,
chatroomMembers: String?, chatroomMembers: String?,
) { ) {
val notId = id.hashCode() val notId = id.hashCode()
@@ -187,8 +190,11 @@ object NotificationUtils {
if (isDuplicate(notId)) return if (isDuplicate(notId)) return
val bitmap = pictureUrl?.let { loadBitmap(it, applicationContext) } val bitmap = pictureUrl?.let { loadBitmap(it, applicationContext) }
val accountBitmap = accountPictureUrl?.let { loadBitmap(it, applicationContext) }
val senderIcon = bitmap?.let { IconCompat.createWithBitmap(it) } val senderIcon = bitmap?.let { IconCompat.createWithBitmap(it) }
val accountIcon = accountBitmap?.let { IconCompat.createWithBitmap(it) }
val sender = val sender =
Person Person
.Builder() .Builder()
@@ -198,8 +204,13 @@ object NotificationUtils {
val messagingStyle = val messagingStyle =
NotificationCompat NotificationCompat
.MessagingStyle(Person.Builder().setName("Me").build()) .MessagingStyle(
.addMessage(messageBody, time * 1000, sender) Person
.Builder()
.setName("Me")
.setIcon(accountIcon)
.build(),
).addMessage(messageBody, time * 1000, sender)
val contentIntent = val contentIntent =
Intent(applicationContext, MainActivity::class.java).apply { data = uri.toUri() } Intent(applicationContext, MainActivity::class.java).apply { data = uri.toUri() }
@@ -405,7 +405,9 @@ private fun NavigateIfIntentRequested(
actionableNextPage?.let { nextRoute -> actionableNextPage?.let { nextRoute ->
val npub = runCatching { URI(intentNextPage.removePrefix("nostr:")).findParameterValue("account") }.getOrNull() val npub = runCatching { URI(intentNextPage.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
if (npub != null && accountSessionManager.currentAccountNPub() != npub) { if (npub != null && accountSessionManager.currentAccountNPub() != npub) {
accountSessionManager.checkAndSwitchUserSync(npub, nextRoute) accountSessionManager.checkAndSwitchUserSync(npub) { account ->
uriToRoute(intentNextPage, account)
}
} else { } else {
val currentRoute = getRouteWithArguments(nextRoute::class, nav.controller) val currentRoute = getRouteWithArguments(nextRoute::class, nav.controller)
if (!isSameRoute(currentRoute, nextRoute)) { if (!isSameRoute(currentRoute, nextRoute)) {
@@ -461,7 +463,9 @@ private fun NavigateIfIntentRequested(
scope.launch { scope.launch {
val npub = runCatching { URI(uri.removePrefix("nostr:")).findParameterValue("account") }.getOrNull() val npub = runCatching { URI(uri.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
if (npub != null && accountSessionManager.currentAccountNPub() != npub) { if (npub != null && accountSessionManager.currentAccountNPub() != npub) {
accountSessionManager.checkAndSwitchUserSync(npub, newPage) accountSessionManager.checkAndSwitchUserSync(npub) { newAccount ->
uriToRoute(uri, newAccount)
}
} else { } else {
val currentRoute = getRouteWithArguments(newPage::class, nav.controller) val currentRoute = getRouteWithArguments(newPage::class, nav.controller)
if (!isSameRoute(currentRoute, newPage)) { if (!isSameRoute(currentRoute, newPage)) {
@@ -112,11 +112,11 @@ class AccountSessionManager(
} }
} }
private suspend fun loginWithDefaultAccount(route: Route? = null) { private suspend fun loginWithDefaultAccount(routeBuilder: ((account: Account) -> Route?)? = null) {
val accountSettings = localPreferences.loadAccountConfigFromEncryptedStorage() val accountSettings = localPreferences.loadAccountConfigFromEncryptedStorage()
if (accountSettings != null) { if (accountSettings != null) {
startUI(accountSettings, route) startUI(accountSettings, routeBuilder)
} else { } else {
requestLoginUI() requestLoginUI()
} }
@@ -184,11 +184,11 @@ class AccountSessionManager(
fun startUI( fun startUI(
accountSettings: AccountSettings, accountSettings: AccountSettings,
route: Route? = null, routeBuilder: ((account: Account) -> Route?)? = null,
) { ) {
val account = accountsCache.loadAccount(accountSettings) val account = accountsCache.loadAccount(accountSettings)
_accountContent.update { _accountContent.update {
AccountState.LoggedIn(account, route) AccountState.LoggedIn(account, routeBuilder?.invoke(account))
} }
} }
@@ -280,7 +280,7 @@ class AccountSessionManager(
localPreferences.setDefaultAccount(accountSettings) localPreferences.setDefaultAccount(accountSettings)
startUI(accountSettings, route = Route.ImportFollowsSelectUser) startUI(accountSettings, routeBuilder = { Route.ImportFollowsSelectUser })
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
delay(2000) // waits for the new user to connect to the new relays. delay(2000) // waits for the new user to connect to the new relays.
@@ -329,12 +329,12 @@ class AccountSessionManager(
suspend fun checkAndSwitchUserSync( suspend fun checkAndSwitchUserSync(
npub: String, npub: String,
route: Route, routeBuilder: ((account: Account) -> Route?)? = null,
): Boolean { ): Boolean {
if (npub != localPreferences.currentAccount()) { if (npub != localPreferences.currentAccount()) {
val account = localPreferences.allSavedAccounts().firstOrNull { it.npub == npub } val account = localPreferences.allSavedAccounts().firstOrNull { it.npub == npub }
if (account != null) { if (account != null) {
switchUserSync(account, route) switchUserSync(account, routeBuilder)
return true return true
} }
} }
@@ -343,10 +343,10 @@ class AccountSessionManager(
private suspend fun switchUserSync( private suspend fun switchUserSync(
accountInfo: AccountInfo, accountInfo: AccountInfo,
route: Route? = null, routeBuilder: ((account: Account) -> Route?)? = null,
) { ) {
localPreferences.switchToAccount(accountInfo) localPreferences.switchToAccount(accountInfo)
loginWithDefaultAccount(route) loginWithDefaultAccount(routeBuilder)
} }
fun currentAccountNPub() = fun currentAccountNPub() =