mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-28 09:56:45 +02:00
Adds a New Message Tagger to Chats (tags Notes and Users by default) and Private Message (doesn't tag Users and Notes)
This commit is contained in:
@@ -402,10 +402,11 @@ class Account(
|
|||||||
LocalCache.consume(signedEvent)
|
LocalCache.consume(signedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendChannelMessage(message: String, toChannel: String, replyingTo: Note? = null, mentions: List<User>?) {
|
fun sendChannelMessage(message: String, toChannel: String, replyTo: List<Note>?, mentions: List<User>?) {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable()) return
|
||||||
|
|
||||||
val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null }
|
// val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null }
|
||||||
|
val repliesToHex = replyTo?.map { it.idHex }
|
||||||
val mentionsHex = mentions?.map { it.pubkeyHex }
|
val mentionsHex = mentions?.map { it.pubkeyHex }
|
||||||
|
|
||||||
val signedEvent = ChannelMessageEvent.create(
|
val signedEvent = ChannelMessageEvent.create(
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.actions
|
package com.vitorpamplona.amethyst.ui.actions
|
||||||
|
|
||||||
|
import com.vitorpamplona.amethyst.model.Channel
|
||||||
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.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.model.parseDirtyWordForKey
|
import com.vitorpamplona.amethyst.model.parseDirtyWordForKey
|
||||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||||
|
|
||||||
class NewMessageProcessor(var originalNote: Note?, var mentions: List<User>?, var replyTos: List<Note>?, var message: String) {
|
class NewMessageTagger(var channel: Channel?, var mentions: List<User>?, var replyTos: List<Note>?, var message: String) {
|
||||||
|
|
||||||
open fun addUserToMentions(user: User) {
|
open fun addUserToMentions(user: User) {
|
||||||
mentions = if (mentions?.contains(user) == true) mentions else mentions?.plus(user) ?: listOf(user)
|
mentions = if (mentions?.contains(user) == true) mentions else mentions?.plus(user) ?: listOf(user)
|
||||||
@@ -19,12 +20,12 @@ class NewMessageProcessor(var originalNote: Note?, var mentions: List<User>?, va
|
|||||||
|
|
||||||
open fun tagIndex(user: User): Int {
|
open fun tagIndex(user: User): Int {
|
||||||
// Postr Events assembles replies before mentions in the tag order
|
// Postr Events assembles replies before mentions in the tag order
|
||||||
return (if (originalNote?.channel() != null) 1 else 0) + (replyTos?.size ?: 0) + (mentions?.indexOf(user) ?: 0)
|
return (if (channel != null) 1 else 0) + (replyTos?.size ?: 0) + (mentions?.indexOf(user) ?: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun tagIndex(note: Note): Int {
|
open fun tagIndex(note: Note): Int {
|
||||||
// Postr Events assembles replies before mentions in the tag order
|
// Postr Events assembles replies before mentions in the tag order
|
||||||
return (if (originalNote?.channel() != null) 1 else 0) + (replyTos?.indexOf(note) ?: 0)
|
return (if (channel != null) 1 else 0) + (replyTos?.indexOf(note) ?: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
|
@@ -15,7 +15,6 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.vitorpamplona.amethyst.model.*
|
import com.vitorpamplona.amethyst.model.*
|
||||||
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.isValidURL
|
import com.vitorpamplona.amethyst.ui.components.isValidURL
|
||||||
import com.vitorpamplona.amethyst.ui.components.noProtocolUrlValidator
|
import com.vitorpamplona.amethyst.ui.components.noProtocolUrlValidator
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -56,7 +55,6 @@ open class NewPostViewModel : ViewModel() {
|
|||||||
// Invoices
|
// Invoices
|
||||||
var wantsInvoice by mutableStateOf(false)
|
var wantsInvoice by mutableStateOf(false)
|
||||||
|
|
||||||
|
|
||||||
open fun load(account: Account, replyingTo: Note?, quote: Note?) {
|
open fun load(account: Account, replyingTo: Note?, quote: Note?) {
|
||||||
originalNote = replyingTo
|
originalNote = replyingTo
|
||||||
replyingTo?.let { replyNote ->
|
replyingTo?.let { replyNote ->
|
||||||
@@ -84,83 +82,18 @@ open class NewPostViewModel : ViewModel() {
|
|||||||
this.account = account
|
this.account = account
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun addUserToMentions(user: User) {
|
|
||||||
mentions = if (mentions?.contains(user) == true) mentions else mentions?.plus(user) ?: listOf(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun addNoteToReplyTos(note: Note) {
|
|
||||||
note.author?.let { addUserToMentions(it) }
|
|
||||||
replyTos = if (replyTos?.contains(note) == true) replyTos else replyTos?.plus(note) ?: listOf(note)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun tagIndex(user: User): Int {
|
|
||||||
// Postr Events assembles replies before mentions in the tag order
|
|
||||||
return (if (originalNote?.channel() != null) 1 else 0) + (replyTos?.size ?: 0) + (mentions?.indexOf(user) ?: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun tagIndex(note: Note): Int {
|
|
||||||
// Postr Events assembles replies before mentions in the tag order
|
|
||||||
return (if (originalNote?.channel() != null) 1 else 0) + (replyTos?.indexOf(note) ?: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sendPost() {
|
fun sendPost() {
|
||||||
// adds all references to mentions and reply tos
|
val tagger = NewMessageTagger(originalNote?.channel(), mentions, replyTos, message.text)
|
||||||
message.text.split('\n').forEach { paragraph: String ->
|
tagger.run()
|
||||||
paragraph.split(' ').forEach { word: String ->
|
|
||||||
val results = parseDirtyWordForKey(word)
|
|
||||||
|
|
||||||
if (results?.key?.type == Nip19.Type.USER) {
|
|
||||||
addUserToMentions(LocalCache.getOrCreateUser(results.key.hex))
|
|
||||||
} else if (results?.key?.type == Nip19.Type.NOTE) {
|
|
||||||
addNoteToReplyTos(LocalCache.getOrCreateNote(results.key.hex))
|
|
||||||
} else if (results?.key?.type == Nip19.Type.EVENT) {
|
|
||||||
addNoteToReplyTos(LocalCache.getOrCreateNote(results.key.hex))
|
|
||||||
} else if (results?.key?.type == Nip19.Type.ADDRESS) {
|
|
||||||
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
|
|
||||||
if (note != null) {
|
|
||||||
addNoteToReplyTos(note)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tags the text in the correct order.
|
|
||||||
val newMessage = message.text.split('\n').map { paragraph: String ->
|
|
||||||
paragraph.split(' ').map { word: String ->
|
|
||||||
val results = parseDirtyWordForKey(word)
|
|
||||||
if (results?.key?.type == Nip19.Type.USER) {
|
|
||||||
val user = LocalCache.getOrCreateUser(results.key.hex)
|
|
||||||
|
|
||||||
"#[${tagIndex(user)}]${results.restOfWord}"
|
|
||||||
} else if (results?.key?.type == Nip19.Type.NOTE) {
|
|
||||||
val note = LocalCache.getOrCreateNote(results.key.hex)
|
|
||||||
|
|
||||||
"#[${tagIndex(note)}]${results.restOfWord}"
|
|
||||||
} else if (results?.key?.type == Nip19.Type.EVENT) {
|
|
||||||
val note = LocalCache.getOrCreateNote(results.key.hex)
|
|
||||||
|
|
||||||
"#[${tagIndex(note)}]${results.restOfWord}"
|
|
||||||
} else if (results?.key?.type == Nip19.Type.ADDRESS) {
|
|
||||||
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
|
|
||||||
if (note != null) {
|
|
||||||
"#[${tagIndex(note)}]${results.restOfWord}"
|
|
||||||
} else {
|
|
||||||
word
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
word
|
|
||||||
}
|
|
||||||
}.joinToString(" ")
|
|
||||||
}.joinToString("\n")
|
|
||||||
|
|
||||||
if (wantsPoll) {
|
if (wantsPoll) {
|
||||||
account?.sendPoll(newMessage, replyTos, mentions, pollOptions, valueMaximum, valueMinimum, consensusThreshold, closedAt)
|
account?.sendPoll(tagger.message, tagger.replyTos, tagger.mentions, pollOptions, valueMaximum, valueMinimum, consensusThreshold, closedAt)
|
||||||
} else if (originalNote?.channel() != null) {
|
} else if (originalNote?.channel() != null) {
|
||||||
account?.sendChannelMessage(newMessage, originalNote!!.channel()!!.idHex, originalNote!!, mentions)
|
account?.sendChannelMessage(tagger.message, tagger.channel!!.idHex, tagger.replyTos, tagger.mentions)
|
||||||
} else if (originalNote?.event is PrivateDmEvent) {
|
} else if (originalNote?.event is PrivateDmEvent) {
|
||||||
account?.sendPrivateMessage(newMessage, originalNote!!.author!!.pubkeyHex, originalNote!!, mentions)
|
account?.sendPrivateMessage(tagger.message, originalNote!!.author!!.pubkeyHex, originalNote!!, tagger.mentions)
|
||||||
} else {
|
} else {
|
||||||
account?.sendPost(newMessage, replyTos, mentions)
|
account?.sendPost(tagger.message, tagger.replyTos, tagger.mentions)
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
@@ -230,7 +230,6 @@ fun ChatroomMessageCompose(
|
|||||||
if (!innerQuote && !replyTo.isNullOrEmpty()) {
|
if (!innerQuote && !replyTo.isNullOrEmpty()) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
replyTo.toSet().mapIndexed { _, note ->
|
replyTo.toSet().mapIndexed { _, note ->
|
||||||
if (note.event != null) {
|
|
||||||
ChatroomMessageCompose(
|
ChatroomMessageCompose(
|
||||||
note,
|
note,
|
||||||
null,
|
null,
|
||||||
@@ -243,7 +242,6 @@ fun ChatroomMessageCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
val event = note.event
|
val event = note.event
|
||||||
|
@@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.model.Channel
|
|||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
|
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
|
||||||
import com.vitorpamplona.amethyst.ui.actions.NewChannelView
|
import com.vitorpamplona.amethyst.ui.actions.NewChannelView
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||||
import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel
|
import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
||||||
import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery
|
import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery
|
||||||
@@ -213,7 +214,9 @@ fun ChannelScreen(
|
|||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
PostButton(
|
PostButton(
|
||||||
onPost = {
|
onPost = {
|
||||||
account.sendChannelMessage(channelScreenModel.message.text, channel.idHex, replyTo.value, null)
|
val tagger = NewMessageTagger(channel, listOfNotNull(replyTo.value?.author), listOfNotNull(replyTo.value), channelScreenModel.message.text)
|
||||||
|
tagger.run()
|
||||||
|
account.sendChannelMessage(tagger.message, channel.idHex, tagger.replyTos, tagger.mentions)
|
||||||
channelScreenModel.message = TextFieldValue("")
|
channelScreenModel.message = TextFieldValue("")
|
||||||
replyTo.value = null
|
replyTo.value = null
|
||||||
feedViewModel.invalidateData() // Don't wait a full second before updating
|
feedViewModel.invalidateData() // Don't wait a full second before updating
|
||||||
|
Reference in New Issue
Block a user