add draft in the home feed
This commit is contained in:
@@ -56,6 +56,7 @@ import com.vitorpamplona.quartz.events.ClassifiedsEvent
|
|||||||
import com.vitorpamplona.quartz.events.Contact
|
import com.vitorpamplona.quartz.events.Contact
|
||||||
import com.vitorpamplona.quartz.events.ContactListEvent
|
import com.vitorpamplona.quartz.events.ContactListEvent
|
||||||
import com.vitorpamplona.quartz.events.DeletionEvent
|
import com.vitorpamplona.quartz.events.DeletionEvent
|
||||||
|
import com.vitorpamplona.quartz.events.DraftEvent
|
||||||
import com.vitorpamplona.quartz.events.EmojiPackEvent
|
import com.vitorpamplona.quartz.events.EmojiPackEvent
|
||||||
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
|
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
|
||||||
import com.vitorpamplona.quartz.events.EmojiUrl
|
import com.vitorpamplona.quartz.events.EmojiUrl
|
||||||
@@ -1422,6 +1423,7 @@ class Account(
|
|||||||
relayList: List<Relay>? = null,
|
relayList: List<Relay>? = null,
|
||||||
geohash: String? = null,
|
geohash: String? = null,
|
||||||
nip94attachments: List<FileHeaderEvent>? = null,
|
nip94attachments: List<FileHeaderEvent>? = null,
|
||||||
|
draftTag: String?,
|
||||||
) {
|
) {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable()) return
|
||||||
|
|
||||||
@@ -1445,20 +1447,28 @@ class Account(
|
|||||||
nip94attachments = nip94attachments,
|
nip94attachments = nip94attachments,
|
||||||
forkedFrom = forkedFrom,
|
forkedFrom = forkedFrom,
|
||||||
signer = signer,
|
signer = signer,
|
||||||
|
isDraft = draftTag != null,
|
||||||
) {
|
) {
|
||||||
Client.send(it, relayList = relayList)
|
if (draftTag != null) {
|
||||||
LocalCache.justConsume(it, null)
|
DraftEvent.create(draftTag, it, signer) { draftEvent ->
|
||||||
|
Client.send(draftEvent, relayList = relayList)
|
||||||
// broadcast replied notes
|
LocalCache.justConsume(draftEvent, null)
|
||||||
replyingTo?.let {
|
|
||||||
LocalCache.getNoteIfExists(replyingTo)?.event?.let {
|
|
||||||
Client.send(it, relayList = relayList)
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
replyTo?.forEach { it.event?.let { Client.send(it, relayList = relayList) } }
|
Client.send(it, relayList = relayList)
|
||||||
addresses?.forEach {
|
LocalCache.justConsume(it, null)
|
||||||
LocalCache.getAddressableNoteIfExists(it.toTag())?.event?.let {
|
|
||||||
Client.send(it, relayList = relayList)
|
// broadcast replied notes
|
||||||
|
replyingTo?.let {
|
||||||
|
LocalCache.getNoteIfExists(replyingTo)?.event?.let {
|
||||||
|
Client.send(it, relayList = relayList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replyTo?.forEach { it.event?.let { Client.send(it, relayList = relayList) } }
|
||||||
|
addresses?.forEach {
|
||||||
|
LocalCache.getAddressableNoteIfExists(it.toTag())?.event?.let {
|
||||||
|
Client.send(it, relayList = relayList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2210,6 +2220,7 @@ class Account(
|
|||||||
|
|
||||||
fun cachedDecryptContent(note: Note): String? {
|
fun cachedDecryptContent(note: Note): String? {
|
||||||
val event = note.event
|
val event = note.event
|
||||||
|
|
||||||
return if (event is PrivateDmEvent && isWriteable()) {
|
return if (event is PrivateDmEvent && isWriteable()) {
|
||||||
event.cachedContentFor(signer)
|
event.cachedContentFor(signer)
|
||||||
} else if (event is LnZapRequestEvent && event.isPrivateZap() && isWriteable()) {
|
} else if (event is LnZapRequestEvent && event.isPrivateZap() && isWriteable()) {
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import com.vitorpamplona.quartz.events.CommunityListEvent
|
|||||||
import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent
|
import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent
|
||||||
import com.vitorpamplona.quartz.events.ContactListEvent
|
import com.vitorpamplona.quartz.events.ContactListEvent
|
||||||
import com.vitorpamplona.quartz.events.DeletionEvent
|
import com.vitorpamplona.quartz.events.DeletionEvent
|
||||||
|
import com.vitorpamplona.quartz.events.DraftEvent
|
||||||
import com.vitorpamplona.quartz.events.EmojiPackEvent
|
import com.vitorpamplona.quartz.events.EmojiPackEvent
|
||||||
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
|
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
|
||||||
import com.vitorpamplona.quartz.events.Event
|
import com.vitorpamplona.quartz.events.Event
|
||||||
@@ -2042,6 +2043,13 @@ object LocalCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun consume(
|
||||||
|
event: DraftEvent,
|
||||||
|
relay: Relay?,
|
||||||
|
) {
|
||||||
|
consumeBaseReplaceable(event, relay)
|
||||||
|
}
|
||||||
|
|
||||||
fun justConsume(
|
fun justConsume(
|
||||||
event: Event,
|
event: Event,
|
||||||
relay: Relay?,
|
relay: Relay?,
|
||||||
@@ -2079,6 +2087,7 @@ object LocalCache {
|
|||||||
}
|
}
|
||||||
is ContactListEvent -> consume(event)
|
is ContactListEvent -> consume(event)
|
||||||
is DeletionEvent -> consume(event)
|
is DeletionEvent -> consume(event)
|
||||||
|
is DraftEvent -> consume(event, relay)
|
||||||
is EmojiPackEvent -> consume(event, relay)
|
is EmojiPackEvent -> consume(event, relay)
|
||||||
is EmojiPackSelectionEvent -> consume(event, relay)
|
is EmojiPackSelectionEvent -> consume(event, relay)
|
||||||
is SealedGossipEvent -> consume(event, relay)
|
is SealedGossipEvent -> consume(event, relay)
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ open class Note(val idHex: String) {
|
|||||||
var event: EventInterface? = null
|
var event: EventInterface? = null
|
||||||
var author: User? = null
|
var author: User? = null
|
||||||
var replyTo: List<Note>? = null
|
var replyTo: List<Note>? = null
|
||||||
|
var draft: String? = null
|
||||||
|
|
||||||
// These fields are updated every time an event related to this note is received.
|
// These fields are updated every time an event related to this note is received.
|
||||||
var replies = listOf<Note>()
|
var replies = listOf<Note>()
|
||||||
@@ -183,6 +184,17 @@ open class Note(val idHex: String) {
|
|||||||
|
|
||||||
open fun createdAt() = event?.createdAt()
|
open fun createdAt() = event?.createdAt()
|
||||||
|
|
||||||
|
fun updateDraft(id: String) {
|
||||||
|
draft = id
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isDraft(): Boolean {
|
||||||
|
draft?.let {
|
||||||
|
return it.isNotBlank()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun loadEvent(
|
fun loadEvent(
|
||||||
event: Event,
|
event: Event,
|
||||||
author: User,
|
author: User,
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import com.vitorpamplona.quartz.events.CalendarRSVPEvent
|
|||||||
import com.vitorpamplona.quartz.events.CalendarTimeSlotEvent
|
import com.vitorpamplona.quartz.events.CalendarTimeSlotEvent
|
||||||
import com.vitorpamplona.quartz.events.ChannelMessageEvent
|
import com.vitorpamplona.quartz.events.ChannelMessageEvent
|
||||||
import com.vitorpamplona.quartz.events.ContactListEvent
|
import com.vitorpamplona.quartz.events.ContactListEvent
|
||||||
|
import com.vitorpamplona.quartz.events.DraftEvent
|
||||||
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
|
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
|
||||||
import com.vitorpamplona.quartz.events.Event
|
import com.vitorpamplona.quartz.events.Event
|
||||||
import com.vitorpamplona.quartz.events.EventInterface
|
import com.vitorpamplona.quartz.events.EventInterface
|
||||||
@@ -229,6 +230,16 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createDraftsFilter() =
|
||||||
|
TypedFilter(
|
||||||
|
types = COMMON_FEED_TYPES,
|
||||||
|
filter =
|
||||||
|
JsonFilter(
|
||||||
|
kinds = listOf(DraftEvent.KIND),
|
||||||
|
authors = listOf(account.userProfile().pubkeyHex),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
fun createGiftWrapsToMeFilter() =
|
fun createGiftWrapsToMeFilter() =
|
||||||
TypedFilter(
|
TypedFilter(
|
||||||
types = COMMON_FEED_TYPES,
|
types = COMMON_FEED_TYPES,
|
||||||
@@ -262,22 +273,38 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
if (LocalCache.justVerify(event)) {
|
if (LocalCache.justVerify(event)) {
|
||||||
if (event is GiftWrapEvent) {
|
when (event) {
|
||||||
// Avoid decrypting over and over again if the event already exist.
|
is DraftEvent -> {
|
||||||
val note = LocalCache.getNoteIfExists(event.id)
|
// Avoid decrypting over and over again if the event already exist.
|
||||||
if (note != null && relay.brief in note.relays) return
|
val note = LocalCache.getNoteIfExists(event.id)
|
||||||
|
if (note != null && relay.brief in note.relays) return
|
||||||
|
|
||||||
event.cachedGift(account.signer) { this.consume(it, relay) }
|
event.plainContent(account.signer) {
|
||||||
}
|
LocalCache.justConsume(it, relay)
|
||||||
|
val draftNote = LocalCache.getNoteIfExists(it.id)
|
||||||
|
draftNote?.updateDraft(event.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (event is SealedGossipEvent) {
|
is GiftWrapEvent -> {
|
||||||
// Avoid decrypting over and over again if the event already exist.
|
// Avoid decrypting over and over again if the event already exist.
|
||||||
val note = LocalCache.getNoteIfExists(event.id)
|
val note = LocalCache.getNoteIfExists(event.id)
|
||||||
if (note != null && relay.brief in note.relays) return
|
if (note != null && relay.brief in note.relays) return
|
||||||
|
|
||||||
event.cachedGossip(account.signer) { LocalCache.justConsume(it, relay) }
|
event.cachedGift(account.signer) { this.consume(it, relay) }
|
||||||
} else {
|
}
|
||||||
LocalCache.justConsume(event, relay)
|
|
||||||
|
is SealedGossipEvent -> {
|
||||||
|
// Avoid decrypting over and over again if the event already exist.
|
||||||
|
val note = LocalCache.getNoteIfExists(event.id)
|
||||||
|
if (note != null && relay.brief in note.relays) return
|
||||||
|
|
||||||
|
event.cachedGossip(account.signer) { LocalCache.justConsume(it, relay) }
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
LocalCache.justConsume(event, relay)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,6 +355,7 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
createAccountSettingsFilter(),
|
createAccountSettingsFilter(),
|
||||||
createAccountLastPostsListFilter(),
|
createAccountLastPostsListFilter(),
|
||||||
createOtherAccountsBaseFilter(),
|
createOtherAccountsBaseFilter(),
|
||||||
|
createDraftsFilter(),
|
||||||
)
|
)
|
||||||
.ifEmpty { null }
|
.ifEmpty { null }
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ class Relay(
|
|||||||
val subscriptionId = msgArray.get(1).asText()
|
val subscriptionId = msgArray.get(1).asText()
|
||||||
val event = Event.fromJson(msgArray.get(2))
|
val event = Event.fromJson(msgArray.get(2))
|
||||||
|
|
||||||
// Log.w("Relay", "Relay onEVENT ${event.kind} $url, $subscriptionId ${msgArray.get(2)}")
|
Log.w("Relay", "Relay onEVENT ${event.kind} $url, $subscriptionId ${msgArray.get(2)}")
|
||||||
listeners.forEach {
|
listeners.forEach {
|
||||||
it.onEvent(
|
it.onEvent(
|
||||||
this@Relay,
|
this@Relay,
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
enum class UserSuggestionAnchor {
|
enum class UserSuggestionAnchor {
|
||||||
MAIN_MESSAGE,
|
MAIN_MESSAGE,
|
||||||
@@ -83,6 +84,7 @@ enum class UserSuggestionAnchor {
|
|||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
open class NewPostViewModel() : ViewModel() {
|
open class NewPostViewModel() : ViewModel() {
|
||||||
|
var draftTag: String = UUID.randomUUID().toString()
|
||||||
var accountViewModel: AccountViewModel? = null
|
var accountViewModel: AccountViewModel? = null
|
||||||
var account: Account? = null
|
var account: Account? = null
|
||||||
var requiresNIP24: Boolean = false
|
var requiresNIP24: Boolean = false
|
||||||
@@ -306,11 +308,17 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendPost(relayList: List<Relay>? = null) {
|
fun sendPost(
|
||||||
viewModelScope.launch(Dispatchers.IO) { innerSendPost(relayList) }
|
relayList: List<Relay>? = null,
|
||||||
|
localDraft: String? = null,
|
||||||
|
) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) { innerSendPost(relayList, localDraft) }
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun innerSendPost(relayList: List<Relay>? = null) {
|
private suspend fun innerSendPost(
|
||||||
|
relayList: List<Relay>? = null,
|
||||||
|
localDraft: String?,
|
||||||
|
) {
|
||||||
if (accountViewModel == null) {
|
if (accountViewModel == null) {
|
||||||
cancel()
|
cancel()
|
||||||
return
|
return
|
||||||
@@ -555,11 +563,13 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
relayList = relayList,
|
relayList = relayList,
|
||||||
geohash = geoHash,
|
geohash = geoHash,
|
||||||
nip94attachments = usedAttachments,
|
nip94attachments = usedAttachments,
|
||||||
|
draftTag = draftTag,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (localDraft == null) {
|
||||||
cancel()
|
cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun upload(
|
fun upload(
|
||||||
@@ -693,8 +703,8 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
pTags = pTags?.filter { it != userToRemove }
|
pTags = pTags?.filter { it != userToRemove }
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun saveDraft(message: String) {
|
open fun saveDraft() {
|
||||||
account?.let { LocalPreferences.saveDraft(message, originalNote?.idHex, it) }
|
sendPost(localDraft = draftTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun loadDraft(): String? {
|
open fun loadDraft(): String? {
|
||||||
@@ -708,9 +718,6 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun updateMessage(it: TextFieldValue) {
|
open fun updateMessage(it: TextFieldValue) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
saveDraft(it.text)
|
|
||||||
}
|
|
||||||
message = it
|
message = it
|
||||||
urlPreview = findUrlInMessage()
|
urlPreview = findUrlInMessage()
|
||||||
|
|
||||||
@@ -732,6 +739,10 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
userSuggestions = emptyList()
|
userSuggestions = emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
saveDraft()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun updateToUsers(it: TextFieldValue) {
|
open fun updateToUsers(it: TextFieldValue) {
|
||||||
@@ -755,10 +766,16 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
userSuggestions = emptyList()
|
userSuggestions = emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
saveDraft()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun updateSubject(it: TextFieldValue) {
|
open fun updateSubject(it: TextFieldValue) {
|
||||||
subject = it
|
subject = it
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
saveDraft()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun updateZapForwardTo(it: TextFieldValue) {
|
open fun updateZapForwardTo(it: TextFieldValue) {
|
||||||
@@ -785,6 +802,9 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
userSuggestions = emptyList()
|
userSuggestions = emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
saveDraft()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun autocompleteWithUser(item: User) {
|
open fun autocompleteWithUser(item: User) {
|
||||||
@@ -800,9 +820,6 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
message.text.replaceRange(lastWordStart, it.end, wordToInsert),
|
message.text.replaceRange(lastWordStart, it.end, wordToInsert),
|
||||||
TextRange(lastWordStart + wordToInsert.length, lastWordStart + wordToInsert.length),
|
TextRange(lastWordStart + wordToInsert.length, lastWordStart + wordToInsert.length),
|
||||||
)
|
)
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
saveDraft(message.text)
|
|
||||||
}
|
|
||||||
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.FORWARD_ZAPS) {
|
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.FORWARD_ZAPS) {
|
||||||
forwardZapTo.addItem(item)
|
forwardZapTo.addItem(item)
|
||||||
forwardZapToEditting = TextFieldValue("")
|
forwardZapToEditting = TextFieldValue("")
|
||||||
@@ -833,6 +850,10 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
userSuggestionsMainMessage = null
|
userSuggestionsMainMessage = null
|
||||||
userSuggestions = emptyList()
|
userSuggestions = emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
saveDraft()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newStateMapPollOptions(): SnapshotStateMap<Int, String> {
|
private fun newStateMapPollOptions(): SnapshotStateMap<Int, String> {
|
||||||
@@ -902,8 +923,8 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
nip94attachments = nip94attachments + event
|
nip94attachments = nip94attachments + event
|
||||||
|
|
||||||
message = message.insertUrlAtCursor(imageUrl)
|
message = message.insertUrlAtCursor(imageUrl)
|
||||||
saveDraft(message.text)
|
|
||||||
urlPreview = findUrlInMessage()
|
urlPreview = findUrlInMessage()
|
||||||
|
saveDraft()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError = {
|
onError = {
|
||||||
@@ -945,10 +966,10 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
|
|
||||||
note?.let {
|
note?.let {
|
||||||
message = message.insertUrlAtCursor("nostr:" + it.toNEvent())
|
message = message.insertUrlAtCursor("nostr:" + it.toNEvent())
|
||||||
saveDraft(message.text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
urlPreview = findUrlInMessage()
|
urlPreview = findUrlInMessage()
|
||||||
|
saveDraft()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError = {
|
onError = {
|
||||||
@@ -969,6 +990,7 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
locUtil?.let {
|
locUtil?.let {
|
||||||
location =
|
location =
|
||||||
it.locationStateFlow.mapLatest { it.toGeoHash(GeohashPrecision.KM_5_X_5.digits).toString() }
|
it.locationStateFlow.mapLatest { it.toGeoHash(GeohashPrecision.KM_5_X_5.digits).toString() }
|
||||||
|
saveDraft()
|
||||||
}
|
}
|
||||||
viewModelScope.launch(Dispatchers.IO) { locUtil?.start() }
|
viewModelScope.launch(Dispatchers.IO) { locUtil?.start() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS
|
|||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.quartz.events.ChannelMessageEvent
|
import com.vitorpamplona.quartz.events.ChannelMessageEvent
|
||||||
|
import com.vitorpamplona.quartz.events.DraftEvent
|
||||||
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
|
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
|
||||||
import com.vitorpamplona.quartz.events.MuteListEvent
|
import com.vitorpamplona.quartz.events.MuteListEvent
|
||||||
import com.vitorpamplona.quartz.events.PeopleListEvent
|
import com.vitorpamplona.quartz.events.PeopleListEvent
|
||||||
@@ -69,7 +70,8 @@ class HomeConversationsFeedFilter(val account: Account) : AdditiveFeedFilter<Not
|
|||||||
it.event is TextNoteEvent ||
|
it.event is TextNoteEvent ||
|
||||||
it.event is PollNoteEvent ||
|
it.event is PollNoteEvent ||
|
||||||
it.event is ChannelMessageEvent ||
|
it.event is ChannelMessageEvent ||
|
||||||
it.event is LiveActivitiesChatMessageEvent
|
it.event is LiveActivitiesChatMessageEvent ||
|
||||||
|
it.event is DraftEvent
|
||||||
) &&
|
) &&
|
||||||
(
|
(
|
||||||
isGlobal ||
|
isGlobal ||
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
@@ -51,6 +52,7 @@ import androidx.compose.ui.graphics.Brush
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.compositeOver
|
import androidx.compose.ui.graphics.compositeOver
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.distinctUntilChanged
|
import androidx.lifecycle.distinctUntilChanged
|
||||||
@@ -113,6 +115,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer
|
import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||||
@@ -128,6 +131,7 @@ import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifier
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.boostedNoteModifier
|
import com.vitorpamplona.amethyst.ui.theme.boostedNoteModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.channelNotePictureModifier
|
import com.vitorpamplona.amethyst.ui.theme.channelNotePictureModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.grayText
|
import com.vitorpamplona.amethyst.ui.theme.grayText
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
||||||
import com.vitorpamplona.amethyst.ui.theme.normalNoteModifier
|
import com.vitorpamplona.amethyst.ui.theme.normalNoteModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.normalWithTopMarginNoteModifier
|
import com.vitorpamplona.amethyst.ui.theme.normalWithTopMarginNoteModifier
|
||||||
@@ -1109,10 +1113,26 @@ fun SecondUserInfoRow(
|
|||||||
DisplayPoW(pow)
|
DisplayPoW(pow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note.isDraft()) {
|
||||||
|
Spacer(StdHorzSpacer)
|
||||||
|
DisplayDraft()
|
||||||
|
}
|
||||||
|
|
||||||
DisplayOts(note, accountViewModel)
|
DisplayOts(note, accountViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DisplayDraft() {
|
||||||
|
Text(
|
||||||
|
"Draft",
|
||||||
|
color = MaterialTheme.colorScheme.lessImportantLink,
|
||||||
|
fontSize = Font14SP,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
maxLines = 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FirstUserInfoRow(
|
fun FirstUserInfoRow(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ class AddBountyAmountViewModel : ViewModel() {
|
|||||||
root = null,
|
root = null,
|
||||||
directMentions = setOf(),
|
directMentions = setOf(),
|
||||||
forkedFrom = null,
|
forkedFrom = null,
|
||||||
|
draftTag = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
nextAmount = TextFieldValue("")
|
nextAmount = TextFieldValue("")
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
|||||||
import com.vitorpamplona.amethyst.ui.components.mockAccountViewModel
|
import com.vitorpamplona.amethyst.ui.components.mockAccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routeToMessage
|
import com.vitorpamplona.amethyst.ui.navigation.routeToMessage
|
||||||
import com.vitorpamplona.amethyst.ui.note.BlankNote
|
import com.vitorpamplona.amethyst.ui.note.BlankNote
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.DisplayDraft
|
||||||
import com.vitorpamplona.amethyst.ui.note.HiddenNote
|
import com.vitorpamplona.amethyst.ui.note.HiddenNote
|
||||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||||
@@ -468,6 +469,10 @@ fun NoteMaster(
|
|||||||
DisplayPoW(pow)
|
DisplayPoW(pow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note.isDraft()) {
|
||||||
|
DisplayDraft()
|
||||||
|
}
|
||||||
|
|
||||||
DisplayOts(note, accountViewModel)
|
DisplayOts(note, accountViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.events
|
|||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.encoders.HexKey
|
||||||
|
import com.vitorpamplona.quartz.encoders.Nip19Bech32
|
||||||
import com.vitorpamplona.quartz.signers.NostrSigner
|
import com.vitorpamplona.quartz.signers.NostrSigner
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
@@ -33,26 +34,128 @@ class DraftEvent(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
companion object {
|
@Transient private var decryptedContent: Map<HexKey, Event> = mapOf()
|
||||||
const val KIND = 31234
|
|
||||||
|
@Transient private var citedNotesCache: Set<String>? = null
|
||||||
|
|
||||||
|
fun replyTos(): List<HexKey> {
|
||||||
|
val oldStylePositional = tags.filter { it.size > 1 && it.size <= 3 && it[0] == "e" }.map { it[1] }
|
||||||
|
val newStyleReply = tags.lastOrNull { it.size > 3 && it[0] == "e" && it[3] == "reply" }?.get(1)
|
||||||
|
val newStyleRoot = tags.lastOrNull { it.size > 3 && it[0] == "e" && it[3] == "root" }?.get(1)
|
||||||
|
|
||||||
|
val newStyleReplyTos = listOfNotNull(newStyleReply, newStyleRoot)
|
||||||
|
|
||||||
|
return if (newStyleReplyTos.isNotEmpty()) {
|
||||||
|
newStyleReplyTos
|
||||||
|
} else {
|
||||||
|
oldStylePositional
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun create(
|
fun findCitations(): Set<HexKey> {
|
||||||
dTag: String,
|
citedNotesCache?.let {
|
||||||
originalNote: EventInterface,
|
return it
|
||||||
signer: NostrSigner,
|
}
|
||||||
createdAt: Long = TimeUtils.now(),
|
|
||||||
onReady: (DraftEvent) -> Unit,
|
|
||||||
) {
|
|
||||||
val tags =
|
|
||||||
arrayOf(
|
|
||||||
arrayOf("d", dTag),
|
|
||||||
arrayOf("k", "${originalNote.kind()}"),
|
|
||||||
)
|
|
||||||
|
|
||||||
signer.nip44Encrypt(originalNote.content(), signer.pubKey) {
|
val citations = mutableSetOf<HexKey>()
|
||||||
signer.sign(createdAt, KIND, tags, it, onReady)
|
// Removes citations from replies:
|
||||||
|
val matcher = tagSearch.matcher(content)
|
||||||
|
while (matcher.find()) {
|
||||||
|
try {
|
||||||
|
val tag = matcher.group(1)?.let { tags[it.toInt()] }
|
||||||
|
if (tag != null && tag.size > 1 && tag[0] == "e") {
|
||||||
|
citations.add(tag[1])
|
||||||
|
}
|
||||||
|
if (tag != null && tag.size > 1 && tag[0] == "a") {
|
||||||
|
citations.add(tag[1])
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val matcher2 = Nip19Bech32.nip19regex.matcher(content)
|
||||||
|
while (matcher2.find()) {
|
||||||
|
val type = matcher2.group(2) // npub1
|
||||||
|
val key = matcher2.group(3) // bech32
|
||||||
|
val additionalChars = matcher2.group(4) // additional chars
|
||||||
|
|
||||||
|
if (type != null) {
|
||||||
|
val parsed = Nip19Bech32.parseComponents(type, key, additionalChars)?.entity
|
||||||
|
|
||||||
|
if (parsed != null) {
|
||||||
|
when (parsed) {
|
||||||
|
is Nip19Bech32.NEvent -> citations.add(parsed.hex)
|
||||||
|
is Nip19Bech32.NAddress -> citations.add(parsed.atag)
|
||||||
|
is Nip19Bech32.Note -> citations.add(parsed.hex)
|
||||||
|
is Nip19Bech32.NEmbed -> citations.add(parsed.event.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
citedNotesCache = citations
|
||||||
|
return citations
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tagsWithoutCitations(): List<String> {
|
||||||
|
val repliesTo = replyTos()
|
||||||
|
val tagAddresses =
|
||||||
|
taggedAddresses().filter {
|
||||||
|
it.kind != CommunityDefinitionEvent.KIND &&
|
||||||
|
it.kind != WikiNoteEvent.KIND
|
||||||
|
}.map { it.toTag() }
|
||||||
|
if (repliesTo.isEmpty() && tagAddresses.isEmpty()) return emptyList()
|
||||||
|
|
||||||
|
val citations = findCitations()
|
||||||
|
|
||||||
|
return if (citations.isEmpty()) {
|
||||||
|
repliesTo + tagAddresses
|
||||||
|
} else {
|
||||||
|
repliesTo.filter { it !in citations }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cachedContentFor(): Event? {
|
||||||
|
return decryptedContent[dTag()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun plainContent(
|
||||||
|
signer: NostrSigner,
|
||||||
|
onReady: (Event) -> Unit,
|
||||||
|
) {
|
||||||
|
decryptedContent[dTag()]?.let {
|
||||||
|
onReady(it)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
signer.nip44Decrypt(content, signer.pubKey) { retVal ->
|
||||||
|
val event = runCatching { fromJson(retVal) }.getOrNull() ?: return@nip44Decrypt
|
||||||
|
decryptedContent = decryptedContent + Pair(dTag(), event)
|
||||||
|
|
||||||
|
onReady(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KIND = 31234
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
dTag: String,
|
||||||
|
originalNote: EventInterface,
|
||||||
|
signer: NostrSigner,
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
onReady: (DraftEvent) -> Unit,
|
||||||
|
) {
|
||||||
|
val tags = mutableListOf<Array<String>>()
|
||||||
|
tags.add(arrayOf("d", dTag))
|
||||||
|
tags.add(arrayOf("k", "${originalNote.kind()}"))
|
||||||
|
tags.addAll(originalNote.tags().filter { it.size > 1 && it[0] == "e" })
|
||||||
|
tags.addAll(originalNote.tags().filter { it.size > 1 && it[0] == "a" })
|
||||||
|
|
||||||
|
signer.nip44Encrypt(originalNote.toJson(), signer.pubKey) { encryptedContent ->
|
||||||
|
signer.sign(createdAt, KIND, tags.toTypedArray(), encryptedContent, onReady)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ class EventFactory {
|
|||||||
CommunityPostApprovalEvent(id, pubKey, createdAt, tags, content, sig)
|
CommunityPostApprovalEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
ContactListEvent.KIND -> ContactListEvent(id, pubKey, createdAt, tags, content, sig)
|
ContactListEvent.KIND -> ContactListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
DeletionEvent.KIND -> DeletionEvent(id, pubKey, createdAt, tags, content, sig)
|
DeletionEvent.KIND -> DeletionEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
DraftEvent.KIND -> DraftEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
EmojiPackEvent.KIND -> EmojiPackEvent(id, pubKey, createdAt, tags, content, sig)
|
EmojiPackEvent.KIND -> EmojiPackEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
EmojiPackSelectionEvent.KIND ->
|
EmojiPackSelectionEvent.KIND ->
|
||||||
EmojiPackSelectionEvent(id, pubKey, createdAt, tags, content, sig)
|
EmojiPackSelectionEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.quartz.events
|
package com.vitorpamplona.quartz.events
|
||||||
|
|
||||||
import com.vitorpamplona.quartz.encoders.ATag
|
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.encoders.HexKey
|
||||||
import com.vitorpamplona.quartz.signers.NostrSigner
|
import com.vitorpamplona.quartz.signers.NostrSigner
|
||||||
|
|
||||||
@@ -155,49 +154,4 @@ class NIP24Factory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTextNoteNIP24(
|
|
||||||
msg: String,
|
|
||||||
to: List<HexKey>,
|
|
||||||
signer: NostrSigner,
|
|
||||||
replyTos: List<String>? = null,
|
|
||||||
mentions: List<String>? = null,
|
|
||||||
addresses: List<ATag>?,
|
|
||||||
extraTags: List<String>?,
|
|
||||||
zapReceiver: List<ZapSplitSetup>? = null,
|
|
||||||
markAsSensitive: Boolean = false,
|
|
||||||
replyingTo: String?,
|
|
||||||
root: String?,
|
|
||||||
directMentions: Set<HexKey>,
|
|
||||||
zapRaiserAmount: Long? = null,
|
|
||||||
geohash: String? = null,
|
|
||||||
onReady: (Result) -> Unit,
|
|
||||||
) {
|
|
||||||
val senderPublicKey = signer.pubKey
|
|
||||||
|
|
||||||
TextNoteEvent.create(
|
|
||||||
msg = msg,
|
|
||||||
signer = signer,
|
|
||||||
replyTos = replyTos,
|
|
||||||
mentions = mentions,
|
|
||||||
zapReceiver = zapReceiver,
|
|
||||||
root = root,
|
|
||||||
extraTags = extraTags,
|
|
||||||
addresses = addresses,
|
|
||||||
directMentions = directMentions,
|
|
||||||
replyingTo = replyingTo,
|
|
||||||
markAsSensitive = markAsSensitive,
|
|
||||||
zapRaiserAmount = zapRaiserAmount,
|
|
||||||
geohash = geohash,
|
|
||||||
) { senderMessage ->
|
|
||||||
createWraps(senderMessage, to.plus(senderPublicKey).toSet(), signer) { wraps ->
|
|
||||||
onReady(
|
|
||||||
Result(
|
|
||||||
msg = senderMessage,
|
|
||||||
wraps = wraps,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class TextNoteEvent(
|
|||||||
forkedFrom: Event? = null,
|
forkedFrom: Event? = null,
|
||||||
signer: NostrSigner,
|
signer: NostrSigner,
|
||||||
createdAt: Long = TimeUtils.now(),
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
isDraft: Boolean,
|
||||||
onReady: (TextNoteEvent) -> Unit,
|
onReady: (TextNoteEvent) -> Unit,
|
||||||
) {
|
) {
|
||||||
val tags = mutableListOf<Array<String>>()
|
val tags = mutableListOf<Array<String>>()
|
||||||
@@ -121,7 +122,7 @@ class TextNoteEvent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signer.sign(createdAt, KIND, tags.toTypedArray(), msg, onReady)
|
signer.sign(createdAt, KIND, tags.toTypedArray(), msg, onReady, isDraft)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ abstract class NostrSigner(val pubKey: HexKey) {
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
onReady: (T) -> Unit,
|
onReady: (T) -> Unit,
|
||||||
|
isDraft: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
abstract fun nip04Encrypt(
|
abstract fun nip04Encrypt(
|
||||||
|
|||||||
@@ -40,7 +40,13 @@ class NostrSignerExternal(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
onReady: (T) -> Unit,
|
onReady: (T) -> Unit,
|
||||||
|
isDraft: Boolean,
|
||||||
) {
|
) {
|
||||||
|
if (isDraft) {
|
||||||
|
unsignedEvent(createdAt, kind, tags, content, onReady)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val id = Event.generateId(pubKey, createdAt, kind, tags, content).toHexKey()
|
val id = Event.generateId(pubKey, createdAt, kind, tags, content).toHexKey()
|
||||||
|
|
||||||
val event =
|
val event =
|
||||||
@@ -86,6 +92,28 @@ class NostrSignerExternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : Event> unsignedEvent(
|
||||||
|
createdAt: Long,
|
||||||
|
kind: Int,
|
||||||
|
tags: Array<Array<String>>,
|
||||||
|
content: String,
|
||||||
|
onReady: (T) -> Unit,
|
||||||
|
) {
|
||||||
|
val id = Event.generateId(pubKey, createdAt, kind, tags, content)
|
||||||
|
|
||||||
|
onReady(
|
||||||
|
EventFactory.create(
|
||||||
|
id.toHexKey(),
|
||||||
|
pubKey,
|
||||||
|
createdAt,
|
||||||
|
kind,
|
||||||
|
tags,
|
||||||
|
content,
|
||||||
|
"",
|
||||||
|
) as T,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun nip04Encrypt(
|
override fun nip04Encrypt(
|
||||||
decryptedContent: String,
|
decryptedContent: String,
|
||||||
toPublicKey: HexKey,
|
toPublicKey: HexKey,
|
||||||
|
|||||||
@@ -38,9 +38,15 @@ class NostrSignerInternal(val keyPair: KeyPair) : NostrSigner(keyPair.pubKey.toH
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
onReady: (T) -> Unit,
|
onReady: (T) -> Unit,
|
||||||
|
isDraft: Boolean,
|
||||||
) {
|
) {
|
||||||
if (keyPair.privKey == null) return
|
if (keyPair.privKey == null) return
|
||||||
|
|
||||||
|
if (isDraft) {
|
||||||
|
unsignedEvent(createdAt, kind, tags, content, onReady)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (isUnsignedPrivateEvent(kind, tags)) {
|
if (isUnsignedPrivateEvent(kind, tags)) {
|
||||||
// this is a private zap
|
// this is a private zap
|
||||||
signPrivateZap(createdAt, kind, tags, content, onReady)
|
signPrivateZap(createdAt, kind, tags, content, onReady)
|
||||||
@@ -82,6 +88,30 @@ class NostrSignerInternal(val keyPair: KeyPair) : NostrSigner(keyPair.pubKey.toH
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : Event> unsignedEvent(
|
||||||
|
createdAt: Long,
|
||||||
|
kind: Int,
|
||||||
|
tags: Array<Array<String>>,
|
||||||
|
content: String,
|
||||||
|
onReady: (T) -> Unit,
|
||||||
|
) {
|
||||||
|
if (keyPair.privKey == null) return
|
||||||
|
|
||||||
|
val id = Event.generateId(pubKey, createdAt, kind, tags, content)
|
||||||
|
|
||||||
|
onReady(
|
||||||
|
EventFactory.create(
|
||||||
|
id.toHexKey(),
|
||||||
|
pubKey,
|
||||||
|
createdAt,
|
||||||
|
kind,
|
||||||
|
tags,
|
||||||
|
content,
|
||||||
|
"",
|
||||||
|
) as T,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun nip04Encrypt(
|
override fun nip04Encrypt(
|
||||||
decryptedContent: String,
|
decryptedContent: String,
|
||||||
toPublicKey: HexKey,
|
toPublicKey: HexKey,
|
||||||
|
|||||||
Reference in New Issue
Block a user