Voice reply to VoiceEvent/VoiceReplyEvent (KIND 1222/1244) → Creates VoiceReplyEvent (KIND 1244)
Voice reply to TextNoteEvent (KIND 1) → Creates TextNoteEvent (KIND 1) with audio IMeta attachment and proper reply tags
This commit is contained in:
+39
-10
@@ -107,6 +107,9 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PubKeyReferenceTag
|
|||||||
import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser
|
import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser
|
||||||
import com.vitorpamplona.quartz.nip03Timestamp.EmptyOtsResolverBuilder
|
import com.vitorpamplona.quartz.nip03Timestamp.EmptyOtsResolverBuilder
|
||||||
import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent
|
import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent
|
||||||
|
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||||
|
import com.vitorpamplona.quartz.nip10Notes.tags.markedETags
|
||||||
|
import com.vitorpamplona.quartz.nip10Notes.tags.prepareETagsAsReplyTo
|
||||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
|
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
|
||||||
import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent
|
import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent
|
||||||
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
||||||
@@ -134,6 +137,7 @@ import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
|
|||||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||||
import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryResponseEvent
|
import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryResponseEvent
|
||||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||||
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.AudioMeta
|
||||||
import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent
|
||||||
import com.vitorpamplona.quartz.utils.Hex
|
import com.vitorpamplona.quartz.utils.Hex
|
||||||
import com.vitorpamplona.quartz.utils.Log
|
import com.vitorpamplona.quartz.utils.Log
|
||||||
@@ -1154,8 +1158,6 @@ class AccountViewModel(
|
|||||||
context: Context,
|
context: Context,
|
||||||
) {
|
) {
|
||||||
if (isWriteable()) {
|
if (isWriteable()) {
|
||||||
val hint = note.toEventHint<BaseVoiceEvent>() ?: return
|
|
||||||
|
|
||||||
launchSigner {
|
launchSigner {
|
||||||
val uploader = UploadOrchestrator()
|
val uploader = UploadOrchestrator()
|
||||||
val result =
|
val result =
|
||||||
@@ -1171,14 +1173,41 @@ class AccountViewModel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (result is UploadingState.Finished && result.result is UploadOrchestrator.OrchestratorResult.ServerResult) {
|
if (result is UploadingState.Finished && result.result is UploadOrchestrator.OrchestratorResult.ServerResult) {
|
||||||
account.sendVoiceReplyMessage(
|
val audioMeta =
|
||||||
result.result.url,
|
AudioMeta(
|
||||||
result.result.fileHeader.mimeType ?: recording.mimeType,
|
url = result.result.url,
|
||||||
result.result.fileHeader.hash,
|
mimeType = result.result.fileHeader.mimeType ?: recording.mimeType,
|
||||||
recording.duration,
|
hash = result.result.fileHeader.hash,
|
||||||
recording.amplitudes,
|
duration = recording.duration,
|
||||||
hint,
|
waveform = recording.amplitudes,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Check if replying to a voice event
|
||||||
|
val voiceHint = note.toEventHint<BaseVoiceEvent>()
|
||||||
|
if (voiceHint != null) {
|
||||||
|
// Create VoiceReplyEvent (KIND 1244) for voice-to-voice replies
|
||||||
|
account.sendVoiceReplyMessage(
|
||||||
|
result.result.url,
|
||||||
|
result.result.fileHeader.mimeType ?: recording.mimeType,
|
||||||
|
result.result.fileHeader.hash,
|
||||||
|
recording.duration,
|
||||||
|
recording.amplitudes,
|
||||||
|
voiceHint,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Create TextNoteEvent (KIND 1) with audio IMeta for voice replies to regular notes
|
||||||
|
val template =
|
||||||
|
TextNoteEvent.build(audioMeta.url) {
|
||||||
|
val replyingTo = note.toEventHint<TextNoteEvent>()
|
||||||
|
if (replyingTo != null) {
|
||||||
|
val tags = prepareETagsAsReplyTo(replyingTo, null)
|
||||||
|
markedETags(tags)
|
||||||
|
}
|
||||||
|
// Add audio as IMeta attachment
|
||||||
|
add(audioMeta.toIMetaArray())
|
||||||
|
}
|
||||||
|
account.signAndComputeBroadcast(template)
|
||||||
|
}
|
||||||
} else if (result is UploadingState.Error) {
|
} else if (result is UploadingState.Error) {
|
||||||
toastManager.toast(
|
toastManager.toast(
|
||||||
R.string.failed_to_upload_media_no_details,
|
R.string.failed_to_upload_media_no_details,
|
||||||
|
|||||||
+37
-6
@@ -542,18 +542,49 @@ open class ShortNotePostViewModel :
|
|||||||
voiceMetadata?.let { audioMeta ->
|
voiceMetadata?.let { audioMeta ->
|
||||||
// Only create voice reply if original note is also a voice message
|
// Only create voice reply if original note is also a voice message
|
||||||
val originalVoiceHint = originalNote?.toEventHint<BaseVoiceEvent>()
|
val originalVoiceHint = originalNote?.toEventHint<BaseVoiceEvent>()
|
||||||
return if (originalVoiceHint != null) {
|
if (originalVoiceHint != null) {
|
||||||
// Create voice reply event
|
// Create voice reply event (KIND 1244)
|
||||||
VoiceReplyEvent.build(
|
return VoiceReplyEvent.build(
|
||||||
voiceMessage = audioMeta,
|
voiceMessage = audioMeta,
|
||||||
replyingTo = originalVoiceHint,
|
replyingTo = originalVoiceHint,
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
// Create root voice event (no reply or original is not a voice message)
|
// If no original note, create a standalone voice event (KIND 1222)
|
||||||
VoiceEvent.build(
|
if (originalNote == null) {
|
||||||
|
return VoiceEvent.build(
|
||||||
voiceMessage = audioMeta,
|
voiceMessage = audioMeta,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Otherwise, original note exists but is not a voice message
|
||||||
|
// Create a TextNoteEvent (KIND 1) with audio as IMeta attachment
|
||||||
|
return TextNoteEvent.build(audioMeta.url) {
|
||||||
|
val replyingTo = originalNote?.toEventHint<TextNoteEvent>()
|
||||||
|
if (replyingTo != null) {
|
||||||
|
val tags = prepareETagsAsReplyTo(replyingTo, null)
|
||||||
|
tags.forEach {
|
||||||
|
val note = accountViewModel.getNoteIfExists(it.eventId)
|
||||||
|
val ourAuthor = note?.author?.pubkeyHex
|
||||||
|
val ourHint = note?.relayHintUrl()
|
||||||
|
if (it.author == null || it.author?.isBlank() == true) {
|
||||||
|
it.author = ourAuthor
|
||||||
|
} else {
|
||||||
|
if (ourAuthor != null && it.author != ourAuthor) {
|
||||||
|
it.author = ourAuthor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (it.relay == null) {
|
||||||
|
it.relay = ourHint
|
||||||
|
} else {
|
||||||
|
if (ourHint != null && it.relay != ourHint) {
|
||||||
|
it.relay = ourHint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
markedETags(tags)
|
||||||
|
}
|
||||||
|
// Add audio as IMeta attachment
|
||||||
|
add(audioMeta.toIMetaArray())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val tagger =
|
val tagger =
|
||||||
|
|||||||
+29
-7
@@ -37,6 +37,10 @@ import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerType
|
|||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.RecordingResult
|
import com.vitorpamplona.amethyst.ui.actions.uploads.RecordingResult
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||||
|
import com.vitorpamplona.quartz.nip10Notes.tags.markedETags
|
||||||
|
import com.vitorpamplona.quartz.nip10Notes.tags.prepareETagsAsReplyTo
|
||||||
import com.vitorpamplona.quartz.nipA0VoiceMessages.AudioMeta
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.AudioMeta
|
||||||
import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent
|
||||||
import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent
|
||||||
@@ -200,12 +204,6 @@ class VoiceReplyViewModel : ViewModel() {
|
|||||||
is UploadingState.Finished -> {
|
is UploadingState.Finished -> {
|
||||||
when (val orchestratorResult = result.result) {
|
when (val orchestratorResult = result.result) {
|
||||||
is UploadOrchestrator.OrchestratorResult.ServerResult -> {
|
is UploadOrchestrator.OrchestratorResult.ServerResult -> {
|
||||||
val hint = note.toEventHint<BaseVoiceEvent>()
|
|
||||||
if (hint == null) {
|
|
||||||
accountViewModel.toastManager.toast(uploadErrorTitle, uploadVoiceFailed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val audioMeta =
|
val audioMeta =
|
||||||
AudioMeta(
|
AudioMeta(
|
||||||
url = orchestratorResult.url,
|
url = orchestratorResult.url,
|
||||||
@@ -215,7 +213,31 @@ class VoiceReplyViewModel : ViewModel() {
|
|||||||
waveform = recording.amplitudes,
|
waveform = recording.amplitudes,
|
||||||
)
|
)
|
||||||
|
|
||||||
accountViewModel.account.signAndComputeBroadcast(VoiceReplyEvent.build(audioMeta, hint))
|
// Check if replying to a voice event
|
||||||
|
val voiceHint = note.toEventHint<BaseVoiceEvent>()
|
||||||
|
if (voiceHint != null) {
|
||||||
|
// Create VoiceReplyEvent (KIND 1244) for voice-to-voice replies
|
||||||
|
accountViewModel.account.signAndComputeBroadcast(VoiceReplyEvent.build(audioMeta, voiceHint))
|
||||||
|
} else {
|
||||||
|
// Create TextNoteEvent (KIND 1) with audio IMeta for voice replies to regular notes
|
||||||
|
val textHint = note.toEventHint<Event>()
|
||||||
|
if (textHint == null) {
|
||||||
|
accountViewModel.toastManager.toast(uploadErrorTitle, uploadVoiceFailed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val template =
|
||||||
|
TextNoteEvent.build(audioMeta.url) {
|
||||||
|
val replyingTo = note.toEventHint<TextNoteEvent>()
|
||||||
|
if (replyingTo != null) {
|
||||||
|
val tags = prepareETagsAsReplyTo(replyingTo, null)
|
||||||
|
markedETags(tags)
|
||||||
|
}
|
||||||
|
// Add audio as IMeta attachment
|
||||||
|
add(audioMeta.toIMetaArray())
|
||||||
|
}
|
||||||
|
accountViewModel.account.signAndComputeBroadcast(template)
|
||||||
|
}
|
||||||
|
|
||||||
if (server.type != ServerType.NIP95) {
|
if (server.type != ServerType.NIP95) {
|
||||||
accountViewModel.account.settings.changeDefaultFileServer(server)
|
accountViewModel.account.settings.changeDefaultFileServer(server)
|
||||||
|
|||||||
Reference in New Issue
Block a user