diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 4858d1162..c58aa3fda 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -450,7 +450,8 @@ class Account( userProfile().latestContactList?.relays()?.keys?.ifEmpty { null } ?: localRelays.map { it.url }.toSet(), pollOption, - message + message, + toUser?.pubkeyHex ) } LnZapEvent.ZapType.PUBLIC -> { @@ -460,7 +461,8 @@ class Account( ?: localRelays.map { it.url }.toSet(), keyPair.pubKey.toHexKey(), pollOption, - message + message, + toUser?.pubkeyHex ) AmberUtils.openAmber(unsignedEvent) val content = AmberUtils.content[unsignedEvent.id] ?: "" @@ -479,7 +481,8 @@ class Account( ?: localRelays.map { it.url }.toSet(), keyPair.pubKey.toHexKey(), pollOption, - message + message, + toUser?.pubkeyHex ) AmberUtils.openAmber(unsignedEvent, "event") val content = AmberUtils.content[unsignedEvent.id] ?: "" diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt index 8ab310c2f..e449bcc37 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt @@ -3,11 +3,13 @@ package com.vitorpamplona.amethyst.service import android.app.Activity import android.content.Intent import android.net.Uri +import android.util.Log import android.util.LruCache import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache @@ -49,7 +51,7 @@ object AmberUtils { GlobalScope.launch(Dispatchers.Main) { Toast.makeText( Amethyst.instance, - "Sign request rejected", + Amethyst.instance.getString(R.string.sign_request_rejected), Toast.LENGTH_SHORT ).show() } @@ -133,6 +135,7 @@ object AmberUtils { } } + @OptIn(DelicateCoroutinesApi::class) fun openAmber( data: String, type: SignerType, @@ -140,25 +143,36 @@ object AmberUtils { pubKey: HexKey, id: String ) { - ServiceManager.shouldPauseService = false - val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$data")) - val signerType = when (type) { - SignerType.SIGN_EVENT -> "sign_event" - SignerType.NIP04_ENCRYPT -> "nip04_encrypt" - SignerType.NIP04_DECRYPT -> "nip04_decrypt" - SignerType.NIP44_ENCRYPT -> "nip44_encrypt" - SignerType.NIP44_DECRYPT -> "nip44_decrypt" - SignerType.GET_PUBLIC_KEY -> "get_public_key" - SignerType.DECRYPT_ZAP_EVENT -> "decrypt_zap_event" + try { + ServiceManager.shouldPauseService = false + val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$data")) + val signerType = when (type) { + SignerType.SIGN_EVENT -> "sign_event" + SignerType.NIP04_ENCRYPT -> "nip04_encrypt" + SignerType.NIP04_DECRYPT -> "nip04_decrypt" + SignerType.NIP44_ENCRYPT -> "nip44_encrypt" + SignerType.NIP44_DECRYPT -> "nip44_decrypt" + SignerType.GET_PUBLIC_KEY -> "get_public_key" + SignerType.DECRYPT_ZAP_EVENT -> "decrypt_zap_event" + } + intent.putExtra("type", signerType) + intent.putExtra("pubKey", pubKey) + intent.putExtra("id", id) + if (type !== SignerType.GET_PUBLIC_KEY) { + intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) + } + intent.`package` = "com.greenart7c3.nostrsigner" + intentResult.launch(intent) + } catch (e: Exception) { + Log.e("Amber", "Error opening amber", e) + GlobalScope.launch(Dispatchers.Main) { + Toast.makeText( + Amethyst.instance, + Amethyst.instance.getString(R.string.error_opening_amber), + Toast.LENGTH_SHORT + ).show() + } } - intent.putExtra("type", signerType) - intent.putExtra("pubKey", pubKey) - intent.putExtra("id", id) - if (type !== SignerType.GET_PUBLIC_KEY) { - intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) - } - intent.`package` = "com.greenart7c3.nostrsigner" - intentResult.launch(intent) } fun openAmber(event: EventInterface, columnName: String = "signature") { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 4fba01b27..165ebb50b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -14,11 +14,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.fonfon.kgeohash.toGeoHash -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.model.ServersAvailable -import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.model.* import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.LocationUtil import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource @@ -168,13 +164,12 @@ open class NewPostViewModel() : ViewModel() { } fun sendPost(relayList: List? = null) { - try { - val tagger = NewMessageTagger(message.text, mentions, replyTos, originalNote?.channelHex()) - tagger.run() + val tagger = NewMessageTagger(message.text, mentions, replyTos, originalNote?.channelHex()) + tagger.run() - val toUsersTagger = NewMessageTagger(toUsers.text, null, null, null) - toUsersTagger.run() - val dmUsers = toUsersTagger.mentions + val toUsersTagger = NewMessageTagger(toUsers.text, null, null, null) + toUsersTagger.run() + val dmUsers = toUsersTagger.mentions val zapReceiver = if (wantsForwardZapTo) { forwardZapTo?.items?.map { @@ -185,117 +180,112 @@ open class NewPostViewModel() : ViewModel() { isLnAddress = false ) } + } else { + null + } - val geoLocation = locUtil?.locationStateFlow?.value - val geoHash = if (wantsToAddGeoHash && geoLocation != null) { - geoLocation.toGeoHash(GeohashPrecision.KM_5_X_5.digits).toString() + val geoLocation = locUtil?.locationStateFlow?.value + val geoHash = if (wantsToAddGeoHash && geoLocation != null) { + geoLocation.toGeoHash(GeohashPrecision.KM_5_X_5.digits).toString() + } else { + null + } + + val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount else null + + if (originalNote?.channelHex() != null) { + if (originalNote is AddressableEvent && originalNote?.address() != null) { + account?.sendLiveMessage(tagger.message, originalNote?.address()!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) } else { - null + account?.sendChannelMessage(tagger.message, tagger.channelHex!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) } + } else if (originalNote?.event is PrivateDmEvent) { + account?.sendPrivateMessage(tagger.message, originalNote!!.author!!, originalNote!!, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) + } else if (originalNote?.event is ChatMessageEvent) { + val receivers = (originalNote?.event as ChatMessageEvent).recipientsPubKey().plus(originalNote?.author?.pubkeyHex).filterNotNull().toSet().toList() - val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount else null - - if (originalNote?.channelHex() != null) { - if (originalNote is AddressableEvent && originalNote?.address() != null) { - account?.sendLiveMessage(tagger.message, originalNote?.address()!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) - } else { - account?.sendChannelMessage(tagger.message, tagger.channelHex!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) - } - } else if (originalNote?.event is PrivateDmEvent) { - account?.sendPrivateMessage(tagger.message, originalNote!!.author!!, originalNote!!, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) - } else if (originalNote?.event is ChatMessageEvent) { - val receivers = (originalNote?.event as ChatMessageEvent).recipientsPubKey().plus(originalNote?.author?.pubkeyHex).filterNotNull().toSet().toList() - + account?.sendNIP24PrivateMessage( + message = tagger.message, + toUsers = receivers, + subject = subject.text.ifBlank { null }, + replyingTo = originalNote!!, + mentions = tagger.mentions, + wantsToMarkAsSensitive = wantsToMarkAsSensitive, + zapReceiver = zapReceiver, + zapRaiserAmount = localZapRaiserAmount, + geohash = geoHash + ) + } else if (!dmUsers.isNullOrEmpty()) { + if (nip24 || dmUsers.size > 1) { account?.sendNIP24PrivateMessage( message = tagger.message, - toUsers = receivers, + toUsers = dmUsers.map { it.pubkeyHex }, subject = subject.text.ifBlank { null }, - replyingTo = originalNote!!, + replyingTo = tagger.replyTos?.firstOrNull(), mentions = tagger.mentions, wantsToMarkAsSensitive = wantsToMarkAsSensitive, zapReceiver = zapReceiver, zapRaiserAmount = localZapRaiserAmount, geohash = geoHash ) - } else if (!dmUsers.isNullOrEmpty()) { - if (nip24 || dmUsers.size > 1) { - account?.sendNIP24PrivateMessage( - message = tagger.message, - toUsers = dmUsers.map { it.pubkeyHex }, - subject = subject.text.ifBlank { null }, - replyingTo = tagger.replyTos?.firstOrNull(), - mentions = tagger.mentions, - wantsToMarkAsSensitive = wantsToMarkAsSensitive, - zapReceiver = zapReceiver, - zapRaiserAmount = localZapRaiserAmount, - geohash = geoHash - ) - } else { - account?.sendPrivateMessage( - message = tagger.message, - toUser = dmUsers.first().pubkeyHex, - replyingTo = originalNote, - mentions = tagger.mentions, - wantsToMarkAsSensitive = wantsToMarkAsSensitive, - zapReceiver = zapReceiver, - zapRaiserAmount = localZapRaiserAmount, - geohash = geoHash - ) - } } else { - if (wantsPoll) { - account?.sendPoll( - tagger.message, - tagger.replyTos, - tagger.mentions, - pollOptions, - valueMaximum, - valueMinimum, - consensusThreshold, - closedAt, - zapReceiver, - wantsToMarkAsSensitive, - localZapRaiserAmount, - relayList, - geoHash - ) - } else { - // adds markers - val rootId = - (originalNote?.event as? TextNoteEvent)?.root() // if it has a marker as root - ?: originalNote?.replyTo?.firstOrNull { it.event != null && it.replyTo?.isEmpty() == true }?.idHex // if it has loaded events with zero replies in the reply list - ?: originalNote?.replyTo?.firstOrNull()?.idHex // old rules, first item is root. - val replyId = originalNote?.idHex - - account?.sendPost( - message = tagger.message, - replyTo = tagger.replyTos, - mentions = tagger.mentions, - tags = null, - zapReceiver = zapReceiver, - wantsToMarkAsSensitive = wantsToMarkAsSensitive, - zapRaiserAmount = localZapRaiserAmount, - replyingTo = replyId, - root = rootId, - directMentions = tagger.directMentions, - relayList = relayList, - geohash = geoHash - ) - } + account?.sendPrivateMessage( + message = tagger.message, + toUser = dmUsers.first().pubkeyHex, + replyingTo = originalNote, + mentions = tagger.mentions, + wantsToMarkAsSensitive = wantsToMarkAsSensitive, + zapReceiver = zapReceiver, + zapRaiserAmount = localZapRaiserAmount, + geohash = geoHash + ) + } + } else { + if (wantsPoll) { + account?.sendPoll( + tagger.message, + tagger.replyTos, + tagger.mentions, + pollOptions, + valueMaximum, + valueMinimum, + consensusThreshold, + closedAt, + zapReceiver, + wantsToMarkAsSensitive, + localZapRaiserAmount, + relayList, + geoHash + ) + } else { + // adds markers + val rootId = + (originalNote?.event as? TextNoteEvent)?.root() // if it has a marker as root + ?: originalNote?.replyTo?.firstOrNull { it.event != null && it.replyTo?.isEmpty() == true }?.idHex // if it has loaded events with zero replies in the reply list + ?: originalNote?.replyTo?.firstOrNull()?.idHex // old rules, first item is root. + val replyId = originalNote?.idHex + + account?.sendPost( + message = tagger.message, + replyTo = tagger.replyTos, + mentions = tagger.mentions, + tags = null, + zapReceiver = zapReceiver, + wantsToMarkAsSensitive = wantsToMarkAsSensitive, + zapRaiserAmount = localZapRaiserAmount, + replyingTo = replyId, + root = rootId, + directMentions = tagger.directMentions, + relayList = relayList, + geohash = geoHash + ) } - } finally { - cancel() } + + cancel() } - fun upload( - galleryUri: Uri, - description: String, - sensitiveContent: Boolean, - server: ServersAvailable, - context: Context, - relayList: List? = null - ) { + fun upload(galleryUri: Uri, description: String, sensitiveContent: Boolean, server: ServersAvailable, context: Context, relayList: List? = null) { isUploadingImage = true contentToAddUrl = null @@ -313,35 +303,28 @@ open class NewPostViewModel() : ViewModel() { createNIP95Record(it.readBytes(), contentType, description, sensitiveContent, relayList = relayList) } } else { - viewModelScope.launch(Dispatchers.IO) { - ImageUploader.uploadImage( - uri = fileUri, - contentType = contentType, - size = size, - server = server, - contentResolver = contentResolver, - onSuccess = { imageUrl, mimeType -> - if (isNIP94Server(server)) { - createNIP94Record( - imageUrl, - mimeType, - description, - sensitiveContent - ) - } else { - isUploadingImage = false - message = TextFieldValue(message.text + "\n\n" + imageUrl) - urlPreview = findUrlInMessage() - } - }, - onError = { + ImageUploader.uploadImage( + uri = fileUri, + contentType = contentType, + size = size, + server = server, + contentResolver = contentResolver, + onSuccess = { imageUrl, mimeType -> + if (isNIP94Server(server)) { + createNIP94Record(imageUrl, mimeType, description, sensitiveContent) + } else { isUploadingImage = false - viewModelScope.launch { - imageUploadingError.emit("Failed to upload the image / video") - } + message = TextFieldValue(message.text + "\n\n" + imageUrl) + urlPreview = findUrlInMessage() } - ) - } + }, + onError = { + isUploadingImage = false + viewModelScope.launch { + imageUploadingError.emit("Failed to upload the image / video") + } + } + ) } }, onError = { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 73cd53e33..b37888884 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -588,4 +588,6 @@ Lightning wallets not found Paid Wallet %1$s + Error opening Amber + Sign request rejected diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapRequestEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapRequestEvent.kt index 2d2c43282..40f537dec 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapRequestEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapRequestEvent.kt @@ -113,11 +113,12 @@ class LnZapRequestEvent( pubKey: HexKey, pollOption: Int?, message: String, + toUserPubHex: String?, // Overrides in case of Zap Splits createdAt: Long = TimeUtils.now() ): LnZapRequestEvent { var tags = listOf( listOf("e", originalNote.id()), - listOf("p", originalNote.pubKey()), + listOf("p", toUserPubHex ?: originalNote.pubKey()), listOf("relays") + relays ) if (originalNote is AddressableEvent) { @@ -137,12 +138,13 @@ class LnZapRequestEvent( pubKey: HexKey, pollOption: Int?, message: String, + toUserPubHex: String?, createdAt: Long = TimeUtils.now() ): LnZapRequestEvent { val content = message var tags = listOf( listOf("e", originalNote.id()), - listOf("p", originalNote.pubKey()), + listOf("p", toUserPubHex ?: originalNote.pubKey()), listOf("relays") + relays ) if (originalNote is AddressableEvent) { @@ -162,11 +164,12 @@ class LnZapRequestEvent( relays: Set, pollOption: Int?, message: String, + toUserPubHex: String?, // Overrides in case of Zap Splits createdAt: Long = TimeUtils.now() ): LnZapRequestEvent { var tags = listOf( listOf("e", originalNote.id()), - listOf("p", originalNote.pubKey()), + listOf("p", toUserPubHex ?: originalNote.pubKey()), listOf("relays") + relays ) if (originalNote is AddressableEvent) {