mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-22 07:48:27 +00:00
Compare commits
3 Commits
a3e239d33f
...
claude/aut
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de85f6d472 | ||
|
|
aaf1a0e588 | ||
|
|
d88889f653 |
@@ -33,6 +33,7 @@ import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NNote
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NRelay
|
||||
@@ -50,6 +51,13 @@ class NewMessageTagger(
|
||||
val directMentionsNotes = mutableSetOf<Note>()
|
||||
val directMentionsUsers = mutableSetOf<User>()
|
||||
|
||||
companion object {
|
||||
private val bechPrefixes = listOf("npub1", "nprofile1", "nevent1", "note1", "naddr1", "nsec1")
|
||||
|
||||
/** Cheap pre-check so callers can skip parsing plain text that cannot hold a reference. */
|
||||
fun mightContainNostrReference(text: String): Boolean = bechPrefixes.any { text.contains(it, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun addUserToMentions(user: User) {
|
||||
directMentionsUsers.add(user)
|
||||
directMentions.add(user.pubkeyHex)
|
||||
@@ -64,8 +72,15 @@ class NewMessageTagger(
|
||||
eTags = if (eTags?.contains(note) == true) eTags else eTags?.plus(note) ?: listOf(note)
|
||||
}
|
||||
|
||||
suspend fun run() {
|
||||
// adds all references to mentions and reply tos
|
||||
/**
|
||||
* Scans the message for user (npub/nprofile) and event (note/nevent/naddr)
|
||||
* references, resolving each into the users that should be notified — the
|
||||
* referenced user itself, or the referenced event's author. Populates the
|
||||
* mention/reply-to sets (and [pTags]/[eTags]) as a side effect and returns
|
||||
* the resolved users. Does not rewrite the message, so it is cheap enough
|
||||
* to call live as the user types or pastes.
|
||||
*/
|
||||
suspend fun collectMentions(): Set<User> {
|
||||
message.split('\n').forEach { paragraph: String ->
|
||||
paragraph.split(' ').forEach { word: String ->
|
||||
val results = parseDirtyWordForKey(word)
|
||||
@@ -79,7 +94,7 @@ class NewMessageTagger(
|
||||
addUserToMentions(dao.getOrCreateUser(entity.hex))
|
||||
}
|
||||
|
||||
is com.vitorpamplona.quartz.nip19Bech32.entities.NNote -> {
|
||||
is NNote -> {
|
||||
addNoteToReplyTos(dao.getOrCreateNote(entity.hex))
|
||||
}
|
||||
|
||||
@@ -105,6 +120,13 @@ class NewMessageTagger(
|
||||
}
|
||||
}
|
||||
|
||||
return directMentionsUsers
|
||||
}
|
||||
|
||||
suspend fun run() {
|
||||
// adds all references to mentions and reply tos
|
||||
collectMentions()
|
||||
|
||||
// Tags the text in the correct order.
|
||||
message =
|
||||
message
|
||||
@@ -123,7 +145,7 @@ class NewMessageTagger(
|
||||
getNostrAddress(dao.getOrCreateUser(entity.hex).toNProfile(), results.restOfWord)
|
||||
}
|
||||
|
||||
is com.vitorpamplona.quartz.nip19Bech32.entities.NNote -> {
|
||||
is NNote -> {
|
||||
getNostrAddress(dao.getOrCreateNote(entity.hex).toNEvent(), results.restOfWord)
|
||||
}
|
||||
|
||||
|
||||
@@ -786,6 +786,12 @@ open class CommentPostViewModel :
|
||||
notifying = notifying?.filter { it != userToRemove }
|
||||
}
|
||||
|
||||
fun addToReplyList(user: User) {
|
||||
if (notifying?.contains(user) != true) {
|
||||
notifying = (notifying ?: emptyList()).plus(user)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMessageChanged() {
|
||||
urlPreviews.update(message.text.toString())
|
||||
revalidateDraft()
|
||||
@@ -803,9 +809,28 @@ open class CommentPostViewModel :
|
||||
emojiSuggestions?.processCurrentWord(lastWord)
|
||||
}
|
||||
|
||||
addNotifiedUsersFromMessage()
|
||||
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
/**
|
||||
* Surfaces users referenced in the message body (pasted or typed npub/nprofile,
|
||||
* or the author of a pasted note/nevent/naddr) in the notify section, mirroring
|
||||
* what [autocompleteWithUser] does for the @ dropdown. The comment already
|
||||
* notifies these authors at send time via [NewMessageTagger]; this keeps the
|
||||
* notify chips in sync so the user can see (and review) who will be tagged.
|
||||
*/
|
||||
private fun addNotifiedUsersFromMessage() {
|
||||
val text = message.text.toString()
|
||||
if (!NewMessageTagger.mightContainNostrReference(text)) return
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val mentioned = NewMessageTagger(message = text, dao = accountViewModel).collectMentions()
|
||||
mentioned.forEach { addToReplyList(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onForwardZapTextChanged() {
|
||||
if (forwardZapToEditting.selection.collapsed) {
|
||||
val lastWord = forwardZapToEditting.text.toString()
|
||||
@@ -820,6 +845,7 @@ open class CommentPostViewModel :
|
||||
val lastWord = message.currentWord()
|
||||
userSuggestions.replaceCurrentWord(message, lastWord, item)
|
||||
urlPreviews.update(message.text.toString())
|
||||
addToReplyList(item)
|
||||
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.FORWARD_ZAPS) {
|
||||
forwardZapTo.value.addItem(item)
|
||||
forwardZapToEditting.clearText()
|
||||
|
||||
@@ -1352,10 +1352,29 @@ open class ShortNotePostViewModel :
|
||||
emojiSuggestions?.processCurrentWord(lastWord)
|
||||
}
|
||||
|
||||
addNotifiedUsersFromMessage()
|
||||
|
||||
precomputeAiResults()
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
/**
|
||||
* Surfaces users referenced in the message body (pasted or typed npub/nprofile,
|
||||
* or the author of a pasted note/nevent/naddr) in the notify section, mirroring
|
||||
* what [autocompleteWithUser] does for the @ dropdown. The post already notifies
|
||||
* these authors at send time via [NewMessageTagger]; this keeps the notify chips
|
||||
* in sync so the user can see (and review) who will be tagged.
|
||||
*/
|
||||
private fun addNotifiedUsersFromMessage() {
|
||||
val text = message.text.toString()
|
||||
if (!NewMessageTagger.mightContainNostrReference(text)) return
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val mentioned = NewMessageTagger(message = text, dao = accountViewModel).collectMentions()
|
||||
mentioned.forEach { addToReplyList(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onForwardZapTextChanged() {
|
||||
if (forwardZapToEditting.selection.collapsed) {
|
||||
val lastWord = forwardZapToEditting.text.toString()
|
||||
@@ -1370,6 +1389,7 @@ open class ShortNotePostViewModel :
|
||||
val lastWord = message.currentWord()
|
||||
userSuggestions.replaceCurrentWord(message, lastWord, item)
|
||||
urlPreviews.update(message.text.toString())
|
||||
addToReplyList(item)
|
||||
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.FORWARD_ZAPS) {
|
||||
forwardZapTo.value.addItem(item)
|
||||
forwardZapToEditting.clearText()
|
||||
|
||||
Reference in New Issue
Block a user