mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-06 06:44:37 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f94feebbd7 | ||
|
|
82d006f65e | ||
|
|
3a553fa550 | ||
|
|
1e9c3a47a4 | ||
|
|
3d9b4431ad | ||
|
|
6522d74253 | ||
|
|
8a8ae4fb8b | ||
|
|
6cac5fa5e4 | ||
|
|
aa3063acae | ||
|
|
46de90ea65 | ||
|
|
aa44560714 |
@@ -16,8 +16,8 @@ android {
|
||||
applicationId "com.vitorpamplona.amethyst"
|
||||
minSdk libs.versions.android.minSdk.get().toInteger()
|
||||
targetSdk libs.versions.android.targetSdk.get().toInteger()
|
||||
versionCode 415
|
||||
versionName "0.94.0"
|
||||
versionCode 417
|
||||
versionName "0.94.2"
|
||||
buildConfigField "String", "RELEASE_NOTES_ID", "\"fd42b23b9ef792059b1c1a89555443abbb11578f4b3c8430b452559eec7325f3\""
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Stable
|
||||
import coil3.SingletonImageLoader
|
||||
import coil3.annotation.DelicateCoilApi
|
||||
import coil3.gif.AnimatedImageDecoder
|
||||
import coil3.gif.GifDecoder
|
||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
@@ -88,12 +89,13 @@ class ServiceManager(
|
||||
start()
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoilApi::class)
|
||||
private fun start() {
|
||||
Log.d("ServiceManager", "Pre Starting Relay Services $isStarted $account")
|
||||
if (isStarted && account != null) {
|
||||
return
|
||||
}
|
||||
Log.d("ServiceManager", "Starting Relay Services")
|
||||
Log.d("ServiceManager", "Starting Relay Services Tor: ${account?.settings?.torSettings?.torType?.value}")
|
||||
|
||||
val myAccount = account
|
||||
|
||||
@@ -126,7 +128,7 @@ class ServiceManager(
|
||||
?.security
|
||||
?.filterSpamFromStrangers ?: true
|
||||
|
||||
SingletonImageLoader.setSafe {
|
||||
SingletonImageLoader.setUnsafe {
|
||||
Amethyst.instance
|
||||
.imageLoaderBuilder()
|
||||
.components {
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.fonfon.kgeohash.GeoHash
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.BuildConfig
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
import com.vitorpamplona.amethyst.service.LocationState
|
||||
import com.vitorpamplona.amethyst.service.NostrLnZapPaymentResponseDataSource
|
||||
@@ -1063,6 +1064,80 @@ class Account(
|
||||
}
|
||||
}
|
||||
|
||||
class EmojiMedia(
|
||||
val code: String,
|
||||
val url: MediaUrlImage,
|
||||
)
|
||||
|
||||
fun getEmojiPackSelection(): EmojiPackSelectionEvent? = getEmojiPackSelectionNote().event as? EmojiPackSelectionEvent
|
||||
|
||||
fun getEmojiPackSelectionFlow(): StateFlow<NoteState> = getEmojiPackSelectionNote().flow().metadata.stateFlow
|
||||
|
||||
fun getEmojiPackSelectionNote(): AddressableNote = LocalCache.getOrCreateAddressableNote(EmojiPackSelectionEvent.createAddressATag(userProfile().pubkeyHex))
|
||||
|
||||
fun convertEmojiSelectionPack(selection: EmojiPackSelectionEvent?): List<StateFlow<NoteState>>? =
|
||||
selection?.taggedAddresses()?.map {
|
||||
LocalCache
|
||||
.getOrCreateAddressableNote(it)
|
||||
.flow()
|
||||
.metadata.stateFlow
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val liveEmojiSelectionPack: StateFlow<List<StateFlow<NoteState>>?> by lazy {
|
||||
getEmojiPackSelectionFlow()
|
||||
.transformLatest {
|
||||
emit(convertEmojiSelectionPack(it.note.event as? EmojiPackSelectionEvent))
|
||||
}.flowOn(Dispatchers.Default)
|
||||
.stateIn(
|
||||
scope,
|
||||
SharingStarted.Eagerly,
|
||||
runBlocking(Dispatchers.Default) {
|
||||
convertEmojiSelectionPack(getEmojiPackSelection())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fun convertEmojiPack(pack: EmojiPackEvent): List<EmojiMedia> =
|
||||
pack.taggedEmojis().map {
|
||||
EmojiMedia(it.code, MediaUrlImage(it.url))
|
||||
}
|
||||
|
||||
fun mergePack(list: Array<NoteState>): List<EmojiMedia> =
|
||||
list
|
||||
.mapNotNull {
|
||||
val ev = it.note.event as? EmojiPackEvent
|
||||
if (ev != null) {
|
||||
convertEmojiPack(ev)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.flatten()
|
||||
.distinctBy { it.url }
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val myEmojis by lazy {
|
||||
liveEmojiSelectionPack
|
||||
.transformLatest { emojiList ->
|
||||
if (emojiList != null) {
|
||||
emitAll(
|
||||
combineTransform(emojiList) {
|
||||
emit(mergePack(it))
|
||||
},
|
||||
)
|
||||
} else {
|
||||
emit(emptyList())
|
||||
}
|
||||
}.flowOn(Dispatchers.Default)
|
||||
.stateIn(
|
||||
scope,
|
||||
SharingStarted.Eagerly,
|
||||
runBlocking(Dispatchers.Default) {
|
||||
mergePack(convertEmojiSelectionPack(getEmojiPackSelection())?.map { it.value }?.toTypedArray() ?: emptyArray())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fun addPaymentRequestIfNew(paymentRequest: PaymentRequest) {
|
||||
if (
|
||||
!this.transientPaymentRequests.value.contains(paymentRequest) &&
|
||||
@@ -2110,6 +2185,7 @@ class Account(
|
||||
relayList: List<RelaySetupInfo>,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -2137,6 +2213,7 @@ class Account(
|
||||
directMentions = directMentions,
|
||||
geohash = geohash,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
signer = signer,
|
||||
isDraft = draftTag != null,
|
||||
) {
|
||||
@@ -2177,6 +2254,7 @@ class Account(
|
||||
relayList: List<RelaySetupInfo>,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -2199,6 +2277,7 @@ class Account(
|
||||
directMentions = directMentions,
|
||||
geohash = geohash,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
forkedFrom = forkedFrom,
|
||||
signer = signer,
|
||||
isDraft = draftTag != null,
|
||||
@@ -2245,6 +2324,7 @@ class Account(
|
||||
relayList: List<RelaySetupInfo>,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -2265,6 +2345,7 @@ class Account(
|
||||
directMentions = directMentions,
|
||||
geohash = geohash,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
forkedFrom = forkedFrom,
|
||||
signer = signer,
|
||||
isDraft = draftTag != null,
|
||||
@@ -2328,6 +2409,7 @@ class Account(
|
||||
directMentionsUsers: Set<User> = emptySet(),
|
||||
directMentionsNotes: Set<Note> = emptySet(),
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
geohash: String? = null,
|
||||
zapReceiver: List<ZapSplitSetup>? = null,
|
||||
wantsToMarkAsSensitive: Boolean = false,
|
||||
@@ -2371,6 +2453,7 @@ class Account(
|
||||
addressesMentioned = addressesMentioned,
|
||||
eventsMentioned = eventsMentioned,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
geohash = geohash,
|
||||
zapReceiver = zapReceiver,
|
||||
markAsSensitive = wantsToMarkAsSensitive,
|
||||
@@ -2403,6 +2486,7 @@ class Account(
|
||||
addressesMentioned = addressesMentioned,
|
||||
eventsMentioned = eventsMentioned,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
geohash = geohash,
|
||||
zapReceiver = zapReceiver,
|
||||
markAsSensitive = wantsToMarkAsSensitive,
|
||||
@@ -2437,6 +2521,7 @@ class Account(
|
||||
directMentionsUsers: Set<User> = emptySet(),
|
||||
directMentionsNotes: Set<Note> = emptySet(),
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
zapReceiver: List<ZapSplitSetup>? = null,
|
||||
wantsToMarkAsSensitive: Boolean = false,
|
||||
zapRaiserAmount: Long? = null,
|
||||
@@ -2479,6 +2564,7 @@ class Account(
|
||||
addressesMentioned = addressesMentioned,
|
||||
eventsMentioned = eventsMentioned,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
zapReceiver = zapReceiver,
|
||||
markAsSensitive = wantsToMarkAsSensitive,
|
||||
zapRaiserAmount = zapRaiserAmount,
|
||||
@@ -2683,6 +2769,7 @@ class Account(
|
||||
relayList: List<RelaySetupInfo>,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -2705,6 +2792,7 @@ class Account(
|
||||
directMentions = directMentions,
|
||||
geohash = geohash,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
forkedFrom = forkedFrom,
|
||||
signer = signer,
|
||||
isDraft = draftTag != null,
|
||||
@@ -2775,6 +2863,7 @@ class Account(
|
||||
relayList: List<RelaySetupInfo>,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -2835,6 +2924,7 @@ class Account(
|
||||
directMentions: Set<HexKey>,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -2853,6 +2943,7 @@ class Account(
|
||||
directMentions = directMentions,
|
||||
geohash = geohash,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
signer = signer,
|
||||
isDraft = draftTag != null,
|
||||
) {
|
||||
@@ -2881,6 +2972,7 @@ class Account(
|
||||
zapRaiserAmount: Long? = null,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -2899,6 +2991,7 @@ class Account(
|
||||
zapRaiserAmount = zapRaiserAmount,
|
||||
geohash = geohash,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
signer = signer,
|
||||
isDraft = draftTag != null,
|
||||
) {
|
||||
@@ -3043,6 +3136,7 @@ class Account(
|
||||
zapRaiserAmount: Long? = null,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String? = null,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -3061,6 +3155,7 @@ class Account(
|
||||
zapRaiserAmount = zapRaiserAmount,
|
||||
geohash = geohash,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
draftTag = draftTag,
|
||||
signer = signer,
|
||||
) {
|
||||
|
||||
@@ -57,6 +57,7 @@ import com.vitorpamplona.quartz.encoders.Hex
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import com.vitorpamplona.quartz.encoders.IMetaTag
|
||||
import com.vitorpamplona.quartz.encoders.IMetaTagBuilder
|
||||
import com.vitorpamplona.quartz.encoders.Nip30CustomEmoji
|
||||
import com.vitorpamplona.quartz.encoders.toNpub
|
||||
import com.vitorpamplona.quartz.events.AddressableEvent
|
||||
import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
|
||||
@@ -65,6 +66,7 @@ import com.vitorpamplona.quartz.events.ClassifiedsEvent
|
||||
import com.vitorpamplona.quartz.events.CommentEvent
|
||||
import com.vitorpamplona.quartz.events.CommunityDefinitionEvent
|
||||
import com.vitorpamplona.quartz.events.DraftEvent
|
||||
import com.vitorpamplona.quartz.events.EmojiUrl
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import com.vitorpamplona.quartz.events.FileStorageEvent
|
||||
import com.vitorpamplona.quartz.events.FileStorageHeaderEvent
|
||||
@@ -82,7 +84,12 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
@@ -120,6 +127,27 @@ open class NewPostViewModel : ViewModel() {
|
||||
var userSuggestionAnchor: TextRange? = null
|
||||
var userSuggestionsMainMessage: UserSuggestionAnchor? = null
|
||||
|
||||
val emojiSearch: MutableStateFlow<String> = MutableStateFlow("")
|
||||
val emojiSuggestions: StateFlow<List<Account.EmojiMedia>> by lazy {
|
||||
account!!
|
||||
.myEmojis
|
||||
.combine(emojiSearch) { list, search ->
|
||||
if (search.length == 1) {
|
||||
list
|
||||
} else if (search.isNotEmpty()) {
|
||||
val code = search.removePrefix(":")
|
||||
list.filter { it.code.startsWith(code) }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}.flowOn(Dispatchers.Default)
|
||||
.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5000),
|
||||
emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
// DMs
|
||||
var wantsDirectMessage by mutableStateOf(false)
|
||||
var toUsers by mutableStateOf(TextFieldValue(""))
|
||||
@@ -552,6 +580,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
val emojis = findEmoji(tagger.message, account?.myEmojis?.value)
|
||||
val urls = findURLs(tagger.message)
|
||||
val usedAttachments = iMetaAttachments.filter { it.url in urls.toSet() }
|
||||
|
||||
@@ -569,6 +598,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
wantsToMarkAsSensitive = wantsToMarkAsSensitive,
|
||||
zapRaiserAmount = localZapRaiserAmount,
|
||||
relayList = relayList,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else if (wantsExclusiveGeoPost && geoHash != null && (originalNote == null || originalNote?.event is CommentEvent)) {
|
||||
@@ -583,6 +613,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
wantsToMarkAsSensitive = wantsToMarkAsSensitive,
|
||||
zapRaiserAmount = localZapRaiserAmount,
|
||||
relayList = relayList,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else if (originalNote?.channelHex() != null) {
|
||||
@@ -597,6 +628,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
zapRaiserAmount = localZapRaiserAmount,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else {
|
||||
@@ -611,6 +643,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
directMentions = tagger.directMentions,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
}
|
||||
@@ -639,6 +672,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
zapRaiserAmount = localZapRaiserAmount,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else if (!dmUsers.isNullOrEmpty()) {
|
||||
@@ -654,6 +688,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
zapRaiserAmount = localZapRaiserAmount,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else {
|
||||
@@ -708,6 +743,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
relayList = relayList,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else if (originalNote?.event is TorrentCommentEvent) {
|
||||
@@ -747,6 +783,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
relayList = relayList,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
}
|
||||
@@ -776,6 +813,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
relayList = relayList,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else {
|
||||
@@ -795,6 +833,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
relayList = relayList,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else if (wantsProduct) {
|
||||
@@ -814,6 +853,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
relayList = relayList,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
} else {
|
||||
@@ -851,12 +891,23 @@ open class NewPostViewModel : ViewModel() {
|
||||
relayList = relayList,
|
||||
geohash = geoHash,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = localDraft,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun findEmoji(
|
||||
message: String,
|
||||
myEmojiSet: List<Account.EmojiMedia>?,
|
||||
): List<EmojiUrl> {
|
||||
if (myEmojiSet == null) return emptyList()
|
||||
return Nip30CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
||||
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrl(it.code, it.url.url) }
|
||||
}
|
||||
}
|
||||
|
||||
fun upload(
|
||||
alt: String?,
|
||||
sensitiveContent: Boolean,
|
||||
@@ -978,6 +1029,10 @@ open class NewPostViewModel : ViewModel() {
|
||||
userSuggestionAnchor = null
|
||||
userSuggestionsMainMessage = null
|
||||
|
||||
if (emojiSearch.value.isNotEmpty()) {
|
||||
emojiSearch.tryEmit("")
|
||||
}
|
||||
|
||||
draftTag = UUID.randomUUID().toString()
|
||||
|
||||
NostrSearchEventOrUserDataSource.clear()
|
||||
@@ -1029,6 +1084,14 @@ open class NewPostViewModel : ViewModel() {
|
||||
NostrSearchEventOrUserDataSource.clear()
|
||||
userSuggestions = emptyList()
|
||||
}
|
||||
|
||||
if (lastWord.startsWith(":")) {
|
||||
emojiSearch.tryEmit(lastWord)
|
||||
} else {
|
||||
if (emojiSearch.value.isNotBlank()) {
|
||||
emojiSearch.tryEmit("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveDraft()
|
||||
@@ -1132,6 +1195,54 @@ open class NewPostViewModel : ViewModel() {
|
||||
saveDraft()
|
||||
}
|
||||
|
||||
open fun autocompleteWithEmoji(item: Account.EmojiMedia) {
|
||||
userSuggestionAnchor?.let {
|
||||
val lastWord =
|
||||
message.text
|
||||
.substring(0, it.end)
|
||||
.substringAfterLast("\n")
|
||||
.substringAfterLast(" ")
|
||||
val lastWordStart = it.end - lastWord.length
|
||||
val wordToInsert = ":${item.code}:"
|
||||
|
||||
message =
|
||||
TextFieldValue(
|
||||
message.text.replaceRange(lastWordStart, it.end, wordToInsert),
|
||||
TextRange(lastWordStart + wordToInsert.length, lastWordStart + wordToInsert.length),
|
||||
)
|
||||
|
||||
userSuggestionAnchor = null
|
||||
emojiSearch.tryEmit("")
|
||||
}
|
||||
|
||||
saveDraft()
|
||||
}
|
||||
|
||||
open fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
||||
userSuggestionAnchor?.let {
|
||||
val lastWord =
|
||||
message.text
|
||||
.substring(0, it.end)
|
||||
.substringAfterLast("\n")
|
||||
.substringAfterLast(" ")
|
||||
val lastWordStart = it.end - lastWord.length
|
||||
val wordToInsert = item.url.url + " "
|
||||
|
||||
message =
|
||||
TextFieldValue(
|
||||
message.text.replaceRange(lastWordStart, it.end, wordToInsert),
|
||||
TextRange(lastWordStart + wordToInsert.length, lastWordStart + wordToInsert.length),
|
||||
)
|
||||
|
||||
userSuggestionAnchor = null
|
||||
emojiSearch.tryEmit("")
|
||||
}
|
||||
|
||||
urlPreview = findUrlInMessage()
|
||||
|
||||
saveDraft()
|
||||
}
|
||||
|
||||
private fun newStateMapPollOptions(): SnapshotStateMap<Int, String> = mutableStateMapOf(Pair(0, ""), Pair(1, ""))
|
||||
|
||||
fun canPost(): Boolean =
|
||||
|
||||
@@ -91,7 +91,7 @@ fun MultiUserErrorMessageContentPreview() {
|
||||
|
||||
runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
user1 = LocalCache.getOrCreateUser("aabbccaabbccaabbcc")
|
||||
user1 = LocalCache.getOrCreateUser("aaabccaabbccaabbcc")
|
||||
user2 = LocalCache.getOrCreateUser("bbbccabbbccabbbcca")
|
||||
user3 = LocalCache.getOrCreateUser("ccaadaccaadaccaada")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.content.MediaType.Companion.Text
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.OpenInFull
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.distinctUntilChanged
|
||||
import androidx.lifecycle.map
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.UrlImageView
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Composable
|
||||
fun WatchAndLoadMyEmojiList(accountViewModel: AccountViewModel) {
|
||||
LoadAddressableNote(
|
||||
EmojiPackSelectionEvent.createAddressATag(accountViewModel.userProfile().pubkeyHex),
|
||||
accountViewModel,
|
||||
) { emptyNote ->
|
||||
emptyNote?.let { usersEmojiList ->
|
||||
val collections by usersEmojiList
|
||||
.live()
|
||||
.metadata
|
||||
.map { (it.note.event as? EmojiPackSelectionEvent)?.taggedAddresses()?.toImmutableList() }
|
||||
.distinctUntilChanged()
|
||||
.observeAsState((usersEmojiList.event as? EmojiPackSelectionEvent)?.taggedAddresses()?.toImmutableList())
|
||||
|
||||
collections?.forEach {
|
||||
LoadAddressableNote(aTag = it, accountViewModel) {
|
||||
it?.live()?.metadata?.observeAsState()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowEmojiSuggestionList(
|
||||
emojiSuggestions: Flow<List<Account.EmojiMedia>>,
|
||||
onSelect: (Account.EmojiMedia) -> Unit,
|
||||
onFullSize: (Account.EmojiMedia) -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
modifier: Modifier = Modifier.heightIn(0.dp, 200.dp),
|
||||
) {
|
||||
val suggestions by emojiSuggestions.collectAsStateWithLifecycle(emptyList())
|
||||
|
||||
if (suggestions.isNotEmpty()) {
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(top = 10.dp),
|
||||
modifier = modifier,
|
||||
) {
|
||||
items(suggestions) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.clickable { onSelect(it) }.padding(
|
||||
start = 12.dp,
|
||||
end = 12.dp,
|
||||
top = 10.dp,
|
||||
bottom = 10.dp,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = spacedBy(Size10dp),
|
||||
) {
|
||||
Box(Modifier.size(40.dp)) {
|
||||
UrlImageView(it.url, accountViewModel)
|
||||
}
|
||||
Text(it.code, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
|
||||
Box(Modifier.size(40.dp), contentAlignment = Alignment.Center) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
onFullSize(it)
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.OpenInFull,
|
||||
contentDescription = stringRes(R.string.use_direct_url),
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
HorizontalDivider(
|
||||
thickness = DividerThickness,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,6 @@ class UpdateReactionTypeViewModel : ViewModel() {
|
||||
?.value
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun UpdateReactionTypeDialog(
|
||||
onClose: () -> Unit,
|
||||
|
||||
@@ -157,8 +157,10 @@ import com.vitorpamplona.amethyst.ui.note.LoadCityName
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.PollIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.RegularPostIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.ShowUserSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.note.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapSplitIcon
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.MyTextField
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow
|
||||
@@ -209,6 +211,7 @@ fun NewPostScreen(
|
||||
nav: Nav,
|
||||
) {
|
||||
val postViewModel: NewPostViewModel = viewModel()
|
||||
postViewModel.account = accountViewModel.account
|
||||
postViewModel.wantsDirectMessage = enableMessageInterface
|
||||
postViewModel.wantsToAddGeoHash = enableGeolocation
|
||||
|
||||
@@ -278,6 +281,8 @@ fun NewPostScreen(
|
||||
onDispose { activity.removeOnNewIntentListener(consumer) }
|
||||
}
|
||||
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -575,6 +580,14 @@ fun NewPostScreen(
|
||||
modifier = Modifier.heightIn(0.dp, 300.dp),
|
||||
)
|
||||
|
||||
ShowEmojiSuggestionList(
|
||||
postViewModel.emojiSuggestions,
|
||||
postViewModel::autocompleteWithEmoji,
|
||||
postViewModel::autocompleteWithEmojiUrl,
|
||||
accountViewModel,
|
||||
modifier = Modifier.heightIn(0.dp, 300.dp),
|
||||
)
|
||||
|
||||
BottomRowActions(postViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -130,6 +130,7 @@ import com.vitorpamplona.amethyst.ui.note.LikeReaction
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadChannel
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.note.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.ShowUserSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
@@ -397,6 +398,7 @@ private suspend fun innerSendPost(
|
||||
|
||||
val urls = findURLs(tagger.message)
|
||||
val usedAttachments = newPostModel.iMetaAttachments.filter { it.url in urls.toSet() }
|
||||
val emojis = newPostModel.findEmoji(newPostModel.message.text, accountViewModel.account.myEmojis.value)
|
||||
|
||||
if (channel is PublicChatChannel) {
|
||||
accountViewModel.account.sendChannelMessage(
|
||||
@@ -407,6 +409,7 @@ private suspend fun innerSendPost(
|
||||
directMentions = tagger.directMentions,
|
||||
wantsToMarkAsSensitive = false,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = draftTag,
|
||||
)
|
||||
} else if (channel is LiveActivitiesChannel) {
|
||||
@@ -417,6 +420,7 @@ private suspend fun innerSendPost(
|
||||
mentions = tagger.pTags,
|
||||
wantsToMarkAsSensitive = false,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = draftTag,
|
||||
)
|
||||
}
|
||||
@@ -485,6 +489,13 @@ fun EditFieldRow(
|
||||
accountViewModel,
|
||||
)
|
||||
|
||||
ShowEmojiSuggestionList(
|
||||
channelScreenModel.emojiSuggestions,
|
||||
channelScreenModel::autocompleteWithEmoji,
|
||||
channelScreenModel::autocompleteWithEmojiUrl,
|
||||
accountViewModel,
|
||||
)
|
||||
|
||||
MyTextField(
|
||||
value = channelScreenModel.message,
|
||||
onValueChange = { channelScreenModel.updateMessage(it) },
|
||||
|
||||
+10
@@ -95,6 +95,7 @@ import com.vitorpamplona.amethyst.ui.note.IncognitoIconOff
|
||||
import com.vitorpamplona.amethyst.ui.note.IncognitoIconOn
|
||||
import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures
|
||||
import com.vitorpamplona.amethyst.ui.note.QuickActionAlertDialog
|
||||
import com.vitorpamplona.amethyst.ui.note.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.ShowUserSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
@@ -517,6 +518,7 @@ private fun innerSendPost(
|
||||
) {
|
||||
val urls = findURLs(newPostModel.message.text)
|
||||
val usedAttachments = newPostModel.iMetaAttachments.filter { it.url !in urls.toSet() }
|
||||
val emojis = newPostModel.findEmoji(newPostModel.message.text, accountViewModel.account.myEmojis.value)
|
||||
|
||||
if (newPostModel.nip17 || room.users.size > 1 || replyTo.value?.event is NIP17Group) {
|
||||
accountViewModel.account.sendNIP17PrivateMessage(
|
||||
@@ -526,6 +528,7 @@ private fun innerSendPost(
|
||||
mentions = null,
|
||||
wantsToMarkAsSensitive = false,
|
||||
imetas = usedAttachments,
|
||||
emojis = emojis,
|
||||
draftTag = dTag,
|
||||
)
|
||||
} else {
|
||||
@@ -557,6 +560,13 @@ fun PrivateMessageEditFieldRow(
|
||||
accountViewModel,
|
||||
)
|
||||
|
||||
ShowEmojiSuggestionList(
|
||||
channelScreenModel.emojiSuggestions,
|
||||
channelScreenModel::autocompleteWithEmoji,
|
||||
channelScreenModel::autocompleteWithEmojiUrl,
|
||||
accountViewModel,
|
||||
)
|
||||
|
||||
MyTextField(
|
||||
value = channelScreenModel.message,
|
||||
onValueChange = { channelScreenModel.updateMessage(it) },
|
||||
|
||||
@@ -345,6 +345,7 @@
|
||||
<string name="add_content">Přidat do zprávy</string>
|
||||
<string name="add_caption">Přidat titulek</string>
|
||||
<string name="add_caption_example">Můj milý přítel</string>
|
||||
<string name="use_direct_url">Použít přímou URL</string>
|
||||
<string name="content_description">Popis obsahu</string>
|
||||
<string name="content_description_example">Modrá loď na bílé písčité pláži při západu slunce</string>
|
||||
<string name="zap_type">Typ zapsu</string>
|
||||
|
||||
@@ -351,6 +351,7 @@ anz der Bedingungen ist erforderlich</string>
|
||||
<string name="add_content">Zur Nachricht hinzufügen</string>
|
||||
<string name="add_caption">Untertitel hinzufügen</string>
|
||||
<string name="add_caption_example">Mein netter Freund</string>
|
||||
<string name="use_direct_url">Direkte URL verwenden</string>
|
||||
<string name="content_description">Beschreibung des Inhalts</string>
|
||||
<string name="content_description_example">Ein blaues Boot an einem weißen Sandstrand bei Sonnenuntergang</string>
|
||||
<string name="zap_type">Zap-Typ</string>
|
||||
|
||||
@@ -121,6 +121,8 @@
|
||||
<string name="ln_url_outdated">آدرس لایتنینگ(نقل شده)</string>
|
||||
<string name="save_to_gallery">در گالری ذخیره کن</string>
|
||||
<string name="image_saved_to_the_gallery">تصویر در گالری ذخیره شد</string>
|
||||
<string name="video_download_has_started_toast">بارگیری ویدئو آغاز شد…</string>
|
||||
<string name="media_download_has_started_toast">بارگیری رسانه آغاز شد…</string>
|
||||
<string name="failed_to_save_the_image">تصویر ذخیره نشد</string>
|
||||
<string name="video_saved_to_the_gallery">ویدئو در گالری گوشی ذخیره شد</string>
|
||||
<string name="failed_to_save_the_video">ویدئو ذخیره نشد</string>
|
||||
@@ -148,6 +150,8 @@
|
||||
<string name="lightning_address">آدرس لایتنینگ</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">شناسه کلید خصوصی (پسوردتان) را در کلیپبورد کپی می کند(</string>
|
||||
<string name="copy_private_key_to_the_clipboard">کپی کردن کلید خصوصی در کلیپبورد</string>
|
||||
<string name="show_private_key_qr_code">نمایش کد QR کلید خصوصی</string>
|
||||
<string name="show_encrypted_private_key_qr_code">نمایش کد QR کلید خصوصی رمزنگاری شده</string>
|
||||
<string name="copies_the_public_key_to_the_clipboard_for_sharing">کلید عمومی را برای اشتراک گذاری در کلیپبورد ذخیره می کند</string>
|
||||
<string name="copy_public_key_npub_to_the_clipboard">کپی کردن کلید عمومی در کلیپبورد</string>
|
||||
<string name="send_a_direct_message">ارسال پیام مستقیم</string>
|
||||
@@ -335,10 +339,13 @@
|
||||
<string name="hash_verification_info_title">این به چه معناست؟</string>
|
||||
<string name="hash_verification_passed">تصویر از زمان ارسال یکسان است</string>
|
||||
<string name="hash_verification_failed">تصویر تغییر کرده است. ممکن است نویسنده تغییر را ندیده باشد.</string>
|
||||
<string name="content_description_add_media">افزودن رسانه</string>
|
||||
<string name="content_description_add_image">افزودن تصویر</string>
|
||||
<string name="content_description_add_video">افزودن فیلم</string>
|
||||
<string name="content_description_add_document">افزودن مدارک</string>
|
||||
<string name="add_content">افزودن به پیام</string>
|
||||
<string name="add_caption">افزودن عنوان</string>
|
||||
<string name="add_caption_example">دوست عزیز من</string>
|
||||
<string name="content_description">توصیف محتوا</string>
|
||||
<string name="content_description_example">قایقی آبی در ساحل شنی سفید هنگام غروب</string>
|
||||
<string name="zap_type">نوع زپ</string>
|
||||
@@ -352,6 +359,7 @@
|
||||
<string name="zap_type_nonzap">غیرزپ</string>
|
||||
<string name="zap_type_nonzap_explainer">هیچ ردی در نوستر نمی ماند، فقط در شبکه لایتنینگ انجام می شود</string>
|
||||
<string name="file_server">سرور فایل</string>
|
||||
<string name="file_server_description">یک سرور برای بارگذاری این فایل انتخاب کنید</string>
|
||||
<string name="zap_forward_lnAddress">آدرس لایتنینگ یا @User</string>
|
||||
<string name="media_servers">سرورهای رسانه</string>
|
||||
<string name="set_preferred_media_servers">سرورهای مورد علاقه خود برای بارگزاری رسانه را انتخاب کنید.</string>
|
||||
@@ -362,6 +370,14 @@
|
||||
<string name="use_default_servers">استفاده از لیست پیش فرض</string>
|
||||
<string name="add_media_server">افزودن سرور رسانه</string>
|
||||
<string name="delete_media_server">حذف سرور رسانه</string>
|
||||
<string name="uploading_state_ready">آغاز نشده</string>
|
||||
<string name="uploading_state_compressing">فشرده سازی</string>
|
||||
<string name="uploading_state_uploading">درحال بارگذاری</string>
|
||||
<string name="uploading_state_server_processing">در حال پردازش</string>
|
||||
<string name="uploading_state_downloading">در حال بارگیری</string>
|
||||
<string name="uploading_state_hashing">در حال هش کردن</string>
|
||||
<string name="uploading_state_finished">انجام شد</string>
|
||||
<string name="uploading_state_error">خطا</string>
|
||||
<string name="upload_server_relays_nip95">رله های شما (NIP-95)</string>
|
||||
<string name="upload_server_relays_nip95_explainer">فایل ها در رله های شما میزبانی می شوند. NIPجدید: بررسی کنید آیا پشتیبانی می کنند یا خیر </string>
|
||||
<string name="privacy_options">گزینه های حریم خصوصی</string>
|
||||
@@ -583,6 +599,8 @@
|
||||
<string name="copy_url_to_clipboard">کپی URL به کلیپبورد</string>
|
||||
<string name="copy_the_note_id_to_the_clipboard">کپی شناسه یادداشت به کلیپبورد</string>
|
||||
<string name="add_media_to_gallery">افزودن رسانه به گالری</string>
|
||||
<string name="media_added">رسانه افزوده شد</string>
|
||||
<string name="media_added_to_profile_gallery">رسانه به گالری نمایه شما افزوده شد</string>
|
||||
<string name="created_at">ایجاد شده در</string>
|
||||
<string name="rules">قوانین</string>
|
||||
<string name="login_with_external_signer">ورود با Amber</string>
|
||||
@@ -591,6 +609,7 @@
|
||||
<string name="poll_zap_value_min_max_explainer">آراء با مبلغ زپ سنجیده می شوند. می توانید برای جلوگیری از اسپم یک مبلغ حداقل تعیین کنید و برای جلوگیری از دستکاری نتیجه با زپ های بزرگ یک مبلغ حداکثر تعیین کنید. برای اینکه همه آراء ارزش یکسان داشته باشند در هر دو قسمت یک مبلغ را بزنید. یا این قسمت را خالی بگذارید تا هر مبلغ زپی را بپذیرد.</string>
|
||||
<string name="error_dialog_zap_error">زپ فرستاده نمی شود</string>
|
||||
<string name="error_dialog_talk_to_user">پیام به کاربر</string>
|
||||
<string name="error_dialog_talk_to_user_name">پیغام %1$s</string>
|
||||
<string name="error_dialog_button_ok">قبول</string>
|
||||
<string name="relay_information_document_error_assemble_url">به %1$s نرسید: %2$s</string>
|
||||
<string name="relay_information_document_error_failed_to_assemble_url">آدرس NIP-11 ساخته نشد به دلیل %1$s: %2$s</string>
|
||||
@@ -650,6 +669,7 @@
|
||||
<string name="could_not_resolve_check_if_you_are_connected_if_the_server_is_up_and_if_the_lightning_address_is_correct">مشکل %1$s حل نشد. بررسی کنید که به اینترنت متصل باشید، سرور کار کند و آدرس لایتنینگ %2$s صحیح باشد.</string>
|
||||
<string name="could_not_resolve_check_if_you_are_connected_if_the_server_is_up_and_if_the_lightning_address_is_correct_exception">مشکل %1$s حل نشد. بررسی کنید که به اینترنت متصل باشید، سرور کار کند و آدرس لایتنینگ %2$s صحیح باشد. \n\nخطای %3$s</string>
|
||||
<string name="could_not_fetch_invoice_from">صورتحساب از %1$s گرفته نشد</string>
|
||||
<string name="could_not_fetch_invoice_from_details">صورتحساب از %1$s گرفته نشد: %2$s</string>
|
||||
<string name="error_parsing_json_from_lightning_address_check_the_user_s_lightning_setup">خطا در تفسیر JSON از آدرس لایتنینگ. تنظیمات لایتنینگ کاربر را بررسی کنید.</string>
|
||||
<string name="error_parsing_json_from_lightning_address_check_the_user_s_lightning_setup_with_user">خطا در تفسیر JSON از %1$s. تنظیمات لایتنینگ کاربر را بررسی کنید</string>
|
||||
<string name="callback_url_not_found_in_the_user_s_lightning_address_server_configuration">URL بازخوانی در پیکربندی سرور آدرس لایتنینگ یافت نشد</string>
|
||||
@@ -717,7 +737,9 @@
|
||||
<string name="failed_to_upload_media">خطای بارگیری: %1$s</string>
|
||||
<string name="server_did_not_provide_a_url_after_uploading">سرور پس از بارگذاری URL نداد</string>
|
||||
<string name="could_not_download_from_the_server">فایل بارگذاری شده از سرور بارگیری نشد</string>
|
||||
<string name="could_not_check_downloaded_file">فایل بارگیری شده پس از بارگذاری بررسی نشد: %1$s</string>
|
||||
<string name="could_not_prepare_local_file_to_upload">فایل محلی برای بارگذاری آماده نشد: %1$s</string>
|
||||
<string name="failed_to_upload_to_server_with_message">بارگذاری نشد %1$s: %2$s</string>
|
||||
<string name="failed_to_upload_with_message">بارگذاری نشد: %1$s</string>
|
||||
<string name="failed_to_delete_with_message">حذف نشد: %1$s</string>
|
||||
<string name="media_too_big_for_nip95">رسانه برای NIP-95 بسیار بزرگ است</string>
|
||||
@@ -793,6 +815,7 @@
|
||||
<string name="search_relays_not_found_description">ساخت لیستی از رله های مخصوص جستجو و تگ کردن کاربر باعث بهبود این نتایج خواهد شد.</string>
|
||||
<string name="search_relays_not_found_editing">بین ۱-۳ رله بیافزایید تا هنگام جستجوی محتوا یا تگ کردن کاربران از آنها استفاده شود. حتما رله های انتخابی باید NIP-50 را پیادهسازی کرده باشند.</string>
|
||||
<string name="search_relays_not_found_examples">انتخاب های مناسب: \n - nostr.wine\n - relay.nostr.band\n - relay.noswhere.com</string>
|
||||
<string name="dm_upload">بارگذاری پیام خصوصی</string>
|
||||
<string name="relay_settings">تنظیمات رله</string>
|
||||
<string name="public_home_section">رله های خانه/ صندوق خروجی عمومی</string>
|
||||
<string name="public_home_section_explainer">این نوع از رله تمام محتوای شما را ذخریه می کند. امتیست پست های شما را اینجا می فرستد و دیگران از این رله ها برای یافتن محتوای شما استفاده می کنند. بین ۱-۳ رله وارد کنید. این رله ها ممکن است رله های شخصی، پولی، یا عمومی باشند.</string>
|
||||
@@ -875,9 +898,23 @@
|
||||
<string name="http_status_416">بازه براورده نشد - سرور نتوانست مقدار مورد نظر در سربرگ بازه را براورده کند. </string>
|
||||
<string name="http_status_417">انتظارات براورده نشد - سرور نتوانست انتظارات تعیین شده در سربرگ توقع درخواست را براورده کند</string>
|
||||
<string name="http_status_426">ارتقاء الزامی - سرور درخواست را با پروتکل فعلی پردازش نمی کند تا کلاینت پروتکل را ارتقاء دهد.</string>
|
||||
<string name="http_status_500">خطای سرور داخلی - سرور به خطایی غیرمنتظره برخورد و نمی تواند درخواست را کامل کند</string>
|
||||
<string name="http_status_501">انجام نشد - سرور نمی تواند درخواست را انجام دهد یا روش درخواست را تشخیص نمی دهد</string>
|
||||
<string name="http_status_502">درگاه غیرمجاز - سرور به عنوان یک درگاه پاسخی نامعتبر از هاست دریافت کرد</string>
|
||||
<string name="http_status_503">خدمت در دسترس نیست - این اغلب هنگامی که یک سرور بیش از حد شلوغ است یا برای تعمیرات تعطیل است پیش می آید</string>
|
||||
<string name="http_status_504">مهلت درگاه تمام شد - مهلت سرور در نقش یک درگاه یا پراکسی تمام شد، در انتظار پاسخ</string>
|
||||
<string name="http_status_505">نسخه HTTP پشتیبانی نمی شود - سرور ورژن HTTP درخواست را پشتیبانی نمی کند</string>
|
||||
<string name="http_status_507">فضای ذخیره ناکافی - سرور فضای کافی برای پردازش موفق درخواست ندارد</string>
|
||||
<string name="http_status_508">حلقه دیده شد - سرور یک حلقه بینهایت در پردازش این درخواست شناسایی کرد</string>
|
||||
<string name="http_status_511">احراز هویت الزامی - کلاینت برای دسترسی به شبکه می بایست احراز هویت شده باشد</string>
|
||||
<string name="media_servers_nip96_section">سرورهای NIP-96</string>
|
||||
<string name="media_servers_nip96_explainer">هر تعداد سرور که می خواهید اضافه کنید. می توانید بعدا هنگام بارگذاری تصویرتان انتخاب کنید که از کدام سرور استفاده شود</string>
|
||||
<string name="media_servers_blossom_section">سرورهای Blossom</string>
|
||||
<string name="media_servers_blossom_explainer">هر تعداد سرور که می خواهید اضافه کنید. می توانید بعدا هنگام بارگذاری تصویرتان انتخاب کنید که از کدام سرور استفاده شود</string>
|
||||
<string name="add_a_nip96_server">یک سرور NIP-96 بیافزایید</string>
|
||||
<string name="add_a_blossom_server">یک سرور Blossom بیافزایید</string>
|
||||
<string name="delete_all">حذف همه</string>
|
||||
<string name="delete_all_drafts_confirmation">مطمئنید می خواهید حذف کنید؟</string>
|
||||
<string name="stack">استک:</string>
|
||||
<string name="torrent_file">فایل تورنت</string>
|
||||
<string name="torrent_download">بارگيری</string>
|
||||
|
||||
@@ -345,6 +345,7 @@
|
||||
<string name="add_content">Adicionar à mensagem</string>
|
||||
<string name="add_caption">Adicionar uma legenda</string>
|
||||
<string name="add_caption_example">Meu amável amigo</string>
|
||||
<string name="use_direct_url">Usar URL direto</string>
|
||||
<string name="content_description">Descrição do conteúdo</string>
|
||||
<string name="content_description_example">Um barco azul em uma praia de areia branca ao pôr do sol</string>
|
||||
<string name="zap_type">Tipo de Zap</string>
|
||||
|
||||
@@ -345,6 +345,7 @@
|
||||
<string name="add_content">Lägg till Meddelande</string>
|
||||
<string name="add_caption">Lägg till en rubrik</string>
|
||||
<string name="add_caption_example">Min underbara vän</string>
|
||||
<string name="use_direct_url">Använd direkt URL</string>
|
||||
<string name="content_description">Beskrivning av innehållet</string>
|
||||
<string name="content_description_example">En blå båt på en vit sandstrand vid solnedgången</string>
|
||||
<string name="zap_type">Zap Typ</string>
|
||||
|
||||
@@ -377,6 +377,8 @@
|
||||
<string name="add_caption">Add a Caption</string>
|
||||
<string name="add_caption_example">My lovely friend</string>
|
||||
|
||||
<string name="use_direct_url">Use direct URL</string>
|
||||
|
||||
<string name="content_description">Description of the contents</string>
|
||||
<string name="content_description_example">A blue boat in a white sandy beach at sunset</string>
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ class Relay(
|
||||
|
||||
lastConnectTentative = TimeUtils.now()
|
||||
|
||||
socket = socketBuilder.build(url, false, RelayListener(onConnected))
|
||||
socket = socketBuilder.build(url, forceProxy, RelayListener(onConnected))
|
||||
socket?.connect()
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) throw e
|
||||
|
||||
@@ -91,7 +91,8 @@ class RelayPool : Relay.Listener {
|
||||
|
||||
fun loadRelays(relayList: List<Relay>) {
|
||||
check(relayList.isNotEmpty()) { "Relay list should never be empty" }
|
||||
relayList.forEach { addRelay(it) }
|
||||
relayList.forEach { addRelayInner(it) }
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
fun unloadRelays() {
|
||||
@@ -142,9 +143,13 @@ class RelayPool : Relay.Listener {
|
||||
}
|
||||
|
||||
fun addRelay(relay: Relay) {
|
||||
addRelayInner(relay)
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
private fun addRelayInner(relay: Relay) {
|
||||
relay.register(this)
|
||||
relays += relay
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
fun removeRelay(relay: Relay) {
|
||||
|
||||
@@ -20,7 +20,7 @@ firebaseBom = "33.7.0"
|
||||
fragmentKtx = "1.8.5"
|
||||
gms = "4.4.2"
|
||||
jacksonModuleKotlin = "2.18.2"
|
||||
jna = "5.15.0"
|
||||
jna = "5.16.0"
|
||||
jtorctl = "0.4.5.7"
|
||||
junit = "4.13.2"
|
||||
kotlin = "2.1.0"
|
||||
@@ -38,7 +38,7 @@ kotlinx-coroutines-test = "1.10.1"
|
||||
navigationCompose = "2.8.5"
|
||||
okhttp = "5.0.0-alpha.14"
|
||||
runner = "1.6.2"
|
||||
rfc3986 = "0.1.0"
|
||||
rfc3986 = "0.1.2"
|
||||
secp256k1KmpJniAndroid = "0.16.0"
|
||||
securityCryptoKtx = "1.1.0-alpha06"
|
||||
spotless = "6.25.0"
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ dependencies {
|
||||
// LibSodium for ChaCha encryption (NIP-44)
|
||||
// Wait for @aar support in version catalogs
|
||||
implementation "com.goterl:lazysodium-android:5.1.0@aar"
|
||||
implementation 'net.java.dev.jna:jna:5.15.0@aar'
|
||||
implementation 'net.java.dev.jna:jna:5.16.0@aar'
|
||||
|
||||
//implementation (libs.lazysodium.android) { artifact { type = "aar" } }
|
||||
//implementation (libs.jna) { artifact { type = "aar" } }
|
||||
|
||||
@@ -50,6 +50,24 @@ class Nip30CustomEmoji {
|
||||
|
||||
fun createEmojiMap(tags: ImmutableListOfLists<String>): Map<String, String> = tags.lists.filter { it.size > 2 && it[0] == "emoji" }.associate { ":${it[1]}:" to it[2] }
|
||||
|
||||
fun findAllEmojis(input: String): List<String> {
|
||||
val matcher = customEmojiPattern.matcher(input)
|
||||
val emojiNamesInOrder = mutableListOf<String>()
|
||||
while (matcher.find()) {
|
||||
emojiNamesInOrder.add(matcher.group())
|
||||
}
|
||||
return emojiNamesInOrder
|
||||
}
|
||||
|
||||
fun findAllEmojiCodes(input: String): List<String> {
|
||||
val matcher = customEmojiPattern.matcher(input)
|
||||
val emojiNamesInOrder = mutableListOf<String>()
|
||||
while (matcher.find()) {
|
||||
matcher.group(1)?.let { emojiNamesInOrder.add(it) }
|
||||
}
|
||||
return emojiNamesInOrder
|
||||
}
|
||||
|
||||
fun assembleAnnotatedList(
|
||||
input: String,
|
||||
allTags: ImmutableListOfLists<String>?,
|
||||
@@ -65,12 +83,7 @@ class Nip30CustomEmoji {
|
||||
input: String,
|
||||
emojiPairs: Map<String, String>,
|
||||
): ImmutableList<Renderable>? {
|
||||
val matcher = customEmojiPattern.matcher(input)
|
||||
val emojiNamesInOrder = mutableListOf<String>()
|
||||
while (matcher.find()) {
|
||||
emojiNamesInOrder.add(matcher.group())
|
||||
}
|
||||
|
||||
val emojiNamesInOrder = findAllEmojis(input)
|
||||
if (emojiNamesInOrder.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class ChannelMessageEvent(
|
||||
directMentions: Set<HexKey> = emptySet(),
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
isDraft: Boolean,
|
||||
onReady: (ChannelMessageEvent) -> Unit,
|
||||
) {
|
||||
@@ -88,6 +89,7 @@ class ChannelMessageEvent(
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
tags.add(
|
||||
arrayOf("alt", ALT),
|
||||
)
|
||||
|
||||
@@ -84,6 +84,7 @@ class ChatMessageEvent(
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
isDraft: Boolean,
|
||||
onReady: (ChatMessageEvent) -> Unit,
|
||||
) {
|
||||
@@ -103,6 +104,7 @@ class ChatMessageEvent(
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
// tags.add(arrayOf("alt", alt))
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
@@ -115,6 +115,7 @@ class ClassifiedsEvent(
|
||||
zapRaiserAmount: Long?,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
isDraft: Boolean,
|
||||
@@ -190,9 +191,8 @@ class ClassifiedsEvent(
|
||||
}
|
||||
zapRaiserAmount?.let { tags.add(arrayOf("zapraiser", "$it")) }
|
||||
geohash?.let { tags.addAll(geohashMipMap(it)) }
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
imetas?.forEach { tags.add(Nip92MediaAttachments.createTag(it)) }
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
tags.add(arrayOf("alt", ALT))
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
@@ -98,6 +98,7 @@ class CommentEvent(
|
||||
addressesMentioned: Set<ATag> = emptySet(),
|
||||
eventsMentioned: Set<ETag> = emptySet(),
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
geohash: String? = null,
|
||||
zapReceiver: List<ZapSplitSetup>? = null,
|
||||
markAsSensitive: Boolean = false,
|
||||
@@ -120,7 +121,7 @@ class CommentEvent(
|
||||
tags.add(removeTrailingNullsAndEmptyOthers("e", replyingTo.event.id, replyingTo.relay, replyingTo.event.pubKey))
|
||||
tags.add(arrayOf("k", "${replyingTo.event.kind}"))
|
||||
|
||||
create(msg, tags, usersMentioned, addressesMentioned, eventsMentioned, imetas, geohash, zapReceiver, markAsSensitive, zapRaiserAmount, isDraft, signer, createdAt, onReady)
|
||||
create(msg, tags, usersMentioned, addressesMentioned, eventsMentioned, imetas, emojis, geohash, zapReceiver, markAsSensitive, zapRaiserAmount, isDraft, signer, createdAt, onReady)
|
||||
}
|
||||
|
||||
fun replyComment(
|
||||
@@ -130,6 +131,7 @@ class CommentEvent(
|
||||
addressesMentioned: Set<ATag> = emptySet(),
|
||||
eventsMentioned: Set<ETag> = emptySet(),
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
geohash: String? = null,
|
||||
zapReceiver: List<ZapSplitSetup>? = null,
|
||||
markAsSensitive: Boolean = false,
|
||||
@@ -147,7 +149,7 @@ class CommentEvent(
|
||||
tags.add(removeTrailingNullsAndEmptyOthers("e", replyingTo.event.id, replyingTo.relay, replyingTo.event.pubKey))
|
||||
tags.add(arrayOf("k", "${replyingTo.event.kind}"))
|
||||
|
||||
create(msg, tags, usersMentioned, addressesMentioned, eventsMentioned, imetas, geohash, zapReceiver, markAsSensitive, zapRaiserAmount, isDraft, signer, createdAt, onReady)
|
||||
create(msg, tags, usersMentioned, addressesMentioned, eventsMentioned, imetas, emojis, geohash, zapReceiver, markAsSensitive, zapRaiserAmount, isDraft, signer, createdAt, onReady)
|
||||
}
|
||||
|
||||
fun createGeoComment(
|
||||
@@ -157,6 +159,7 @@ class CommentEvent(
|
||||
addressesMentioned: Set<ATag> = emptySet(),
|
||||
eventsMentioned: Set<ETag> = emptySet(),
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
zapReceiver: List<ZapSplitSetup>? = null,
|
||||
markAsSensitive: Boolean = false,
|
||||
zapRaiserAmount: Long? = null,
|
||||
@@ -169,7 +172,7 @@ class CommentEvent(
|
||||
geohash?.let { tags.addAll(rootGeohashMipMap(it)) }
|
||||
tags.add(arrayOf("K", "geo"))
|
||||
|
||||
create(msg, tags, usersMentioned, addressesMentioned, eventsMentioned, imetas, null, zapReceiver, markAsSensitive, zapRaiserAmount, isDraft, signer, createdAt, onReady)
|
||||
create(msg, tags, usersMentioned, addressesMentioned, eventsMentioned, imetas, emojis, null, zapReceiver, markAsSensitive, zapRaiserAmount, isDraft, signer, createdAt, onReady)
|
||||
}
|
||||
|
||||
private fun create(
|
||||
@@ -179,6 +182,7 @@ class CommentEvent(
|
||||
addressesMentioned: Set<ATag> = emptySet(),
|
||||
eventsMentioned: Set<ETag> = emptySet(),
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
geohash: String? = null,
|
||||
zapReceiver: List<ZapSplitSetup>? = null,
|
||||
markAsSensitive: Boolean = false,
|
||||
@@ -202,6 +206,8 @@ class CommentEvent(
|
||||
|
||||
findURLs(msg).forEach { tags.add(arrayOf("r", it)) }
|
||||
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
|
||||
zapReceiver?.forEach {
|
||||
tags.add(arrayOf("zap", it.lnAddressOrPubKeyHex, it.relay ?: "", it.weight.toString()))
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ data class EmojiUrl(
|
||||
) {
|
||||
fun encode(): String = ":$code:$url"
|
||||
|
||||
fun toTagArray() = arrayOf("emoji", code, url)
|
||||
|
||||
companion object {
|
||||
fun decode(encodedEmojiSetup: String): EmojiUrl? {
|
||||
val emojiParts = encodedEmojiSetup.split(":", limit = 3)
|
||||
@@ -71,5 +73,12 @@ data class EmojiUrl(
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun parse(tag: Array<String>): EmojiUrl? =
|
||||
if (tag.size > 2 && tag[0] == "emoji") {
|
||||
EmojiUrl(tag[1], tag[2])
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@ class EmojiPackSelectionEvent(
|
||||
const val FIXED_D_TAG = ""
|
||||
const val ALT = "Emoji selection"
|
||||
|
||||
fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, AdvertisedRelayListEvent.FIXED_D_TAG, null)
|
||||
|
||||
fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, AdvertisedRelayListEvent.FIXED_D_TAG)
|
||||
|
||||
fun create(
|
||||
listOfEmojiPacks: List<ATag>?,
|
||||
signer: NostrSigner,
|
||||
|
||||
@@ -164,7 +164,7 @@ open class Event(
|
||||
ATag.parse(aTagValue, relay)
|
||||
}
|
||||
|
||||
override fun taggedEmojis() = tags.filter { it.size > 2 && it[0] == "emoji" }.map { EmojiUrl(it[1], it[2]) }
|
||||
override fun taggedEmojis() = tags.filter { it.size > 2 && it[0] == "emoji" }.mapNotNull { EmojiUrl.parse(it) }
|
||||
|
||||
override fun isSensitive() =
|
||||
tags.any {
|
||||
|
||||
@@ -92,6 +92,7 @@ class GitReplyEvent(
|
||||
directMentions: Set<HexKey> = emptySet(),
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
forkedFrom: Event? = null,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
@@ -152,6 +153,7 @@ class GitReplyEvent(
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
tags.add(arrayOf("alt", "a git issue reply"))
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
@@ -53,6 +53,7 @@ open class InteractiveStoryBaseEvent(
|
||||
zapRaiserAmount: Long? = null,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
): Array<Array<String>> {
|
||||
val tags = mutableListOf<Array<String>>()
|
||||
findHashtags(content).forEach {
|
||||
@@ -75,6 +76,7 @@ open class InteractiveStoryBaseEvent(
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
return tags.toTypedArray()
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class LiveActivitiesChatMessageEvent(
|
||||
zapRaiserAmount: Long?,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
isDraft: Boolean,
|
||||
onReady: (LiveActivitiesChatMessageEvent) -> Unit,
|
||||
) {
|
||||
@@ -96,6 +97,7 @@ class LiveActivitiesChatMessageEvent(
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
tags.add(arrayOf("alt", ALT))
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
@@ -82,6 +82,7 @@ class NIP17Factory {
|
||||
zapRaiserAmount: Long? = null,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
draftTag: String? = null,
|
||||
onReady: (Result) -> Unit,
|
||||
) {
|
||||
@@ -100,6 +101,7 @@ class NIP17Factory {
|
||||
geohash = geohash,
|
||||
isDraft = draftTag != null,
|
||||
imetas = imetas,
|
||||
emojis = emojis,
|
||||
) { senderMessage ->
|
||||
if (draftTag != null) {
|
||||
onReady(
|
||||
|
||||
@@ -81,6 +81,7 @@ class PollNoteEvent(
|
||||
zapRaiserAmount: Long?,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
isDraft: Boolean,
|
||||
onReady: (PollNoteEvent) -> Unit,
|
||||
) {
|
||||
@@ -108,6 +109,7 @@ class PollNoteEvent(
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
tags.add(arrayOf("alt", ALT))
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
@@ -58,6 +58,7 @@ class TextNoteEvent(
|
||||
directMentions: Set<HexKey> = emptySet(),
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
forkedFrom: Event? = null,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
@@ -123,9 +124,8 @@ class TextNoteEvent(
|
||||
}
|
||||
zapRaiserAmount?.let { tags.add(arrayOf("zapraiser", "$it")) }
|
||||
geohash?.let { tags.addAll(geohashMipMap(it)) }
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
imetas?.forEach { tags.add(Nip92MediaAttachments.createTag(it)) }
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
|
||||
if (isDraft) {
|
||||
signer.assembleRumor(createdAt, KIND, tags.toTypedArray(), msg, onReady)
|
||||
|
||||
@@ -63,6 +63,7 @@ class TorrentCommentEvent(
|
||||
zapRaiserAmount: Long?,
|
||||
geohash: String? = null,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
emojis: List<EmojiUrl>? = null,
|
||||
forkedFrom: Event? = null,
|
||||
isDraft: Boolean,
|
||||
onReady: (TorrentCommentEvent) -> Unit,
|
||||
@@ -126,6 +127,7 @@ class TorrentCommentEvent(
|
||||
imetas?.forEach {
|
||||
tags.add(Nip92MediaAttachments.createTag(it))
|
||||
}
|
||||
emojis?.forEach { tags.add(it.toTagArray()) }
|
||||
tags.add(arrayOf("alt", ALT))
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
Reference in New Issue
Block a user