diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt
index 967bbd4f45..673e6cba60 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.metadata
+import com.vitorpamplona.amethyst.commons.relayClient.assemblers.filterContactCardsByAuthorInTheRelay
import com.vitorpamplona.amethyst.model.nip78AppSpecific.AppSpecificState.Companion.APP_SPECIFIC_DATA_D_TAG
import com.vitorpamplona.quartz.experimental.nipA3.PaymentTargetsEvent
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRelayListEvent
@@ -49,7 +50,6 @@ import com.vitorpamplona.quartz.nip61Nutzaps.info.NutzapInfoEvent
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataEvent
import com.vitorpamplona.quartz.nip85TrustedAssertions.list.TrustProviderListEvent
-import com.vitorpamplona.quartz.nip85TrustedAssertions.users.ContactCardEvent
import com.vitorpamplona.quartz.nip96FileStorage.config.FileServersEvent
import com.vitorpamplona.quartz.nipB7Blossom.BlossomServersEvent
@@ -94,12 +94,6 @@ val AccountInfoAndListsFromKeyKinds2 =
NutzapInfoEvent.KIND,
)
-// The account's own kind:30382 contact cards (nicknames/petnames for other
-// users, NIP-44 encrypted). Addressable: one card per target user, so this is a
-// collection rather than a single replaceable — kept out of the small-limit
-// filters above and given its own filter with a larger limit.
-val AccountContactCardKinds = listOf(ContactCardEvent.KIND)
-
val AmethystMetadataKinds = listOf(AppSpecificDataEvent.KIND)
val AmethystMetadataTagMapFilter = mapOf("d" to listOf(APP_SPECIFIC_DATA_D_TAG))
@@ -131,15 +125,12 @@ fun filterAccountInfoAndListsFromKey(
since = since,
),
),
- RelayBasedFilter(
+ // The account's own kind:30382 contact cards (nicknames, NIP-44 encrypted).
+ // Addressable — one card per target user — hence its own larger-limit filter.
+ filterContactCardsByAuthorInTheRelay(
relay = relay,
- filter =
- Filter(
- kinds = AccountContactCardKinds,
- authors = listOf(pubkey),
- limit = 500,
- since = since,
- ),
+ author = pubkey,
+ since = since,
),
RelayBasedFilter(
relay = relay,
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt
index beb8cb9182..26dcbe7c94 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt
@@ -61,25 +61,11 @@ fun observeUserName(
// Subscribe in the relay for changes in the metadata of this user.
UserFinderFilterAssemblerSubscription(user, accountViewModel)
- val flow =
- remember(user) {
- combine(
- user.metadata().flow,
- accountViewModel.account.contactCards.petNameFlow(user),
- ) { info, petName ->
- petName?.petName ?: info?.info?.bestName() ?: user.pubkeyDisplayHex()
- }.distinctUntilChanged()
- }
-
- val initialName =
- remember(user) {
- accountViewModel.account.contactCards
- .cachedPetName(user)
- ?.petName ?: user.toBestDisplayName()
- }
+ val contactCards = accountViewModel.account.contactCards
+ val flow = remember(user) { contactCards.displayNameFlow(user) }
// Subscribe in the LocalCache for changes that arrive in the device
- return flow.collectAsStateWithLifecycle(initialName)
+ return flow.collectAsStateWithLifecycle(remember(user) { contactCards.cachedDisplayName(user) })
}
/**
@@ -323,7 +309,7 @@ fun observeUserBookmarkCount(
val combined =
remember(user) {
- kotlinx.coroutines.flow.combine(newFlow, oldFlow) { newCount, oldCount ->
+ combine(newFlow, oldFlow) { newCount, oldCount ->
newCount + oldCount
}
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt
index 19474b6c48..bd297744e8 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt
@@ -21,6 +21,7 @@
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.watchers
import com.vitorpamplona.amethyst.commons.model.toHexSet
+import com.vitorpamplona.amethyst.commons.relayClient.assemblers.filterContactCardsToTargetKeysFromTrustedAccountsInTheRelay
import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.SingleSubEoseManager
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.User
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt
index b4d9c028ff..0943395636 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt
@@ -920,13 +920,9 @@ open class CommentPostViewModel :
}
open fun autocompleteWithEmoji(item: EmojiPackState.EmojiMedia) {
- val wordToInsert = ":${item.code}:"
-
- message.replaceCurrentWord(wordToInsert)
+ emojiSuggestions?.autocompleteInto(message, item)
urlPreviews.update(message.text.toString())
- emojiSuggestions?.reset()
-
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt
index 8d4497e18d..ae2542cbcc 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt
@@ -52,6 +52,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
@@ -65,7 +66,6 @@ import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
import com.vitorpamplona.amethyst.ui.note.NoteCompose
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensitivityExplainer
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt
index fc6ed14ce5..2d92030b7b 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt
@@ -764,13 +764,9 @@ class ChatNewMessageViewModel :
}
fun autocompleteWithEmoji(item: EmojiPackState.EmojiMedia) {
- val wordToInsert = ":${item.code}:"
-
- message.replaceCurrentWord(wordToInsert)
+ emojiSuggestions?.autocompleteInto(message, item)
urlPreviews.update(message.text.toString())
- emojiSuggestions?.reset()
-
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt
index 36987b6160..8941be093f 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt
@@ -71,6 +71,7 @@ import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent
import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlImage
import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlVideo
@@ -93,7 +94,6 @@ import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensitivityExplainer
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt
index a089688b21..fc64efe0ab 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt
@@ -51,6 +51,7 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.actions.MentionPreservingInputTransformation
@@ -63,7 +64,6 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList
import com.vitorpamplona.amethyst.ui.note.showCount
import com.vitorpamplona.amethyst.ui.note.timeAheadNoDot
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt
index eab9d48766..377b424bbb 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt
@@ -678,10 +678,7 @@ open class ChannelNewMessageViewModel :
}
open fun autocompleteWithEmoji(item: EmojiPackState.EmojiMedia) {
- val wordToInsert = ":${item.code}:"
- message.replaceCurrentWord(wordToInsert)
-
- emojiSuggestions?.reset()
+ emojiSuggestions?.autocompleteInto(message, item)
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt
index e9f150b50a..f23c35fce7 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt
@@ -37,6 +37,7 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.actions.MentionPreservingInputTransformation
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation
@@ -44,7 +45,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt
index 95cdc5577c..93c8a6b0ae 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt
@@ -83,6 +83,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.actions.MentionPreservingInputTransformation
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation
@@ -99,7 +100,6 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensitivityExplainer
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt
index cb6d7bdc80..47686de456 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt
@@ -692,9 +692,7 @@ class LongFormPostViewModel :
}
fun autocompleteWithEmoji(item: EmojiMedia) {
- val wordToInsert = ":${item.code}:"
- message.replaceCurrentWord(wordToInsert)
- emojiSuggestions?.reset()
+ emojiSuggestions?.autocompleteInto(message, item)
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt
index 6f4fd20c97..9f32382d97 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt
@@ -46,6 +46,7 @@ import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
@@ -58,7 +59,6 @@ import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensitivityExplainer
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt
index f4206076ac..6e7554d7dd 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt
@@ -558,13 +558,9 @@ open class NewProductViewModel :
}
open fun autocompleteWithEmoji(item: EmojiPackState.EmojiMedia) {
- val wordToInsert = ":${item.code}:"
-
- message.replaceCurrentWord(wordToInsert)
+ emojiSuggestions?.autocompleteInto(message, item)
urlPreviews.update(message.text.toString())
- emojiSuggestions?.reset()
-
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt
index 534927c0f1..7453377467 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt
@@ -76,6 +76,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
import com.vitorpamplona.amethyst.ui.actions.mediaServers.FileServerSelectionRow
import com.vitorpamplona.amethyst.ui.actions.uploads.MAX_VOICE_RECORD_SECONDS
@@ -99,7 +100,6 @@ import com.vitorpamplona.amethyst.ui.note.NoteCompose
import com.vitorpamplona.amethyst.ui.note.creators.aihelp.AiWritingHelpPanel
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensitivityExplainer
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt
index 03e6d4c30b..c7ef8c9626 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt
@@ -1610,13 +1610,9 @@ open class ShortNotePostViewModel :
}
open fun autocompleteWithEmoji(item: EmojiMedia) {
- val wordToInsert = ":${item.code}:"
-
- message.replaceCurrentWord(wordToInsert)
+ emojiSuggestions?.autocompleteInto(message, item)
urlPreviews.update(message.text.toString())
- emojiSuggestions?.reset()
-
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt
index f6fa574b3e..88a8f1e51f 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt
@@ -36,13 +36,13 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.actions.MentionPreservingInputTransformation
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt
index dd164b0792..63a55b94c4 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt
@@ -548,10 +548,7 @@ open class NestNewMessageViewModel :
}
open fun autocompleteWithEmoji(item: EmojiPackState.EmojiMedia) {
- val wordToInsert = ":${item.code}:"
- message.replaceCurrentWord(wordToInsert)
-
- emojiSuggestions?.reset()
+ emojiSuggestions?.autocompleteInto(message, item)
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt
index 06d46689e6..f10bd8db4e 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt
@@ -55,6 +55,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.actions.MentionPreservingInputTransformation
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation
@@ -69,7 +70,6 @@ import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
import com.vitorpamplona.amethyst.ui.note.NoteCompose
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensitivityExplainer
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt
index ff9988c888..68ffbf6006 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt
@@ -621,13 +621,9 @@ class NewPublicMessageViewModel :
}
fun autocompleteWithEmoji(item: EmojiPackState.EmojiMedia) {
- val wordToInsert = ":${item.code}:"
-
- message.replaceCurrentWord(wordToInsert)
+ emojiSuggestions?.autocompleteInto(message, item)
urlPreviews.update(message.text.toString())
- emojiSuggestions?.reset()
-
draftTag.newVersion()
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt
index 71e9ac8a38..258f7dbf82 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt
@@ -29,11 +29,13 @@ import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalContext
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
+import com.vitorpamplona.amethyst.commons.nip85TrustedAssertions.ui.EditNicknameDialog
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.components.M3ActionDialog
import com.vitorpamplona.amethyst.ui.components.M3ActionRow
import com.vitorpamplona.amethyst.ui.components.M3ActionSection
import com.vitorpamplona.amethyst.ui.components.util.setText
+import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.note.externalLinkForUser
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
@@ -50,10 +52,13 @@ fun UserProfileDropDownMenu(
val isNicknameDialogOpen = remember { mutableStateOf(false) }
if (isNicknameDialogOpen.value) {
+ // keeps the account's selected emoji packs loaded for the : autocomplete
+ WatchAndLoadMyEmojiList(accountViewModel)
EditNicknameDialog(
user = user,
+ contactCards = accountViewModel.account.contactCards,
+ onSave = { petName, summary -> accountViewModel.updateContactCardPetName(user, petName, summary) },
onDismiss = { isNicknameDialogOpen.value = false },
- accountViewModel = accountViewModel,
)
}
diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml
index c6f381f16e..8c0897ec31 100644
--- a/amethyst/src/main/res/values/strings.xml
+++ b/amethyst/src/main/res/values/strings.xml
@@ -3543,12 +3543,8 @@
Playback
Auto
-
+
Edit nickname
- Nickname
- Shown to you instead of this user\'s name, everywhere in the app. It\'s saved encrypted in your contact card: only you can read it. Type : to use your custom emojis.
- Nickname
- Private note about this user
Cast to device
diff --git a/commons/src/commonMain/composeResources/values/strings.xml b/commons/src/commonMain/composeResources/values/strings.xml
index f7cbf115a9..e50c831382 100644
--- a/commons/src/commonMain/composeResources/values/strings.xml
+++ b/commons/src/commonMain/composeResources/values/strings.xml
@@ -90,4 +90,15 @@
Source:
Servers:
Open
+
+
+ Use direct URL
+
+
+ Nickname
+ Shown to you instead of this user\'s name, everywhere in the app. It\'s saved encrypted in your contact card: only you can read it. Type : to use your custom emojis.
+ Nickname
+ Private note about this user
+ Save
+ Cancel
diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip30CustomEmojis/EmojiSuggestionState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip30CustomEmojis/EmojiSuggestionState.kt
index 08dec98379..0f5e457153 100644
--- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip30CustomEmojis/EmojiSuggestionState.kt
+++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip30CustomEmojis/EmojiSuggestionState.kt
@@ -20,7 +20,9 @@
*/
package com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis
+import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.runtime.Stable
+import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.Flow
@@ -66,4 +68,16 @@ class EmojiSuggestionState(
}
}
}
+
+ /**
+ * Completes the word under the cursor in [field] with the selected emoji's
+ * `:shortcode:` and closes the suggestion list.
+ */
+ fun autocompleteInto(
+ field: TextFieldState,
+ item: EmojiPackState.EmojiMedia,
+ ) {
+ field.replaceCurrentWord(":${item.code}:")
+ reset()
+ }
}
diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip85TrustedAssertions/ContactCardsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip85TrustedAssertions/ContactCardsState.kt
index 9ed53fc670..25b370002d 100644
--- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip85TrustedAssertions/ContactCardsState.kt
+++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip85TrustedAssertions/ContactCardsState.kt
@@ -33,6 +33,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
@@ -112,6 +113,22 @@ class ContactCardsState(
return decryptionCache.cachedPetNameWithEmojis(card)
}
+ /**
+ * The name to render for [target], per the NIP-81 policy: the nickname the
+ * account gave them wins over the profile's own display name, falling back
+ * to the short npub when neither exists.
+ */
+ fun displayNameFlow(target: User): Flow =
+ combine(
+ target.metadata().flow,
+ petNameFlow(target),
+ ) { info, petName ->
+ petName?.petName ?: info?.info?.bestName() ?: target.pubkeyDisplayHex()
+ }.distinctUntilChanged()
+
+ /** Synchronous first value for [displayNameFlow], from already-decrypted data. */
+ fun cachedDisplayName(target: User): String = cachedPetName(target)?.petName ?: target.toBestDisplayName()
+
suspend fun petName(target: HexKey): String? = getCard(target)?.let { decryptionCache.petName(it) }
suspend fun summary(target: HexKey): String? = getCard(target)?.let { decryptionCache.summary(it) }
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/ShowEmojiSuggestionList.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip30CustomEmojis/ui/ShowEmojiSuggestionList.kt
similarity index 86%
rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/ShowEmojiSuggestionList.kt
rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip30CustomEmojis/ui/ShowEmojiSuggestionList.kt
index 953a044747..61d0048193 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/ShowEmojiSuggestionList.kt
+++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip30CustomEmojis/ui/ShowEmojiSuggestionList.kt
@@ -18,7 +18,7 @@
* 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.creators.emojiSuggestions
+package com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement.spacedBy
@@ -39,15 +39,17 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil3.compose.AsyncImage
-import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState
import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState
-import com.vitorpamplona.amethyst.ui.stringRes
-import com.vitorpamplona.amethyst.ui.theme.DividerThickness
-import com.vitorpamplona.amethyst.ui.theme.Size10dp
-import com.vitorpamplona.amethyst.ui.theme.Size40Modifier
+import com.vitorpamplona.amethyst.commons.resources.Res
+import com.vitorpamplona.amethyst.commons.resources.use_direct_url
+import org.jetbrains.compose.resources.stringResource
+
+private val DividerThickness = 0.25.dp
+private val RowSpacing = 10.dp
+private val EmojiSize = Modifier.size(40.dp)
@Composable
fun ShowEmojiSuggestionList(
@@ -73,23 +75,23 @@ fun ShowEmojiSuggestionList(
bottom = 10.dp,
),
verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = spacedBy(Size10dp),
+ horizontalArrangement = spacedBy(RowSpacing),
) {
AsyncImage(
it.link,
contentDescription = it.code,
- modifier = Size40Modifier,
+ modifier = EmojiSize,
)
Text(it.code, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
IconButton(
- modifier = Size40Modifier,
+ modifier = EmojiSize,
onClick = {
onFullSize(it)
},
) {
Icon(
symbol = MaterialSymbols.OpenInFull,
- contentDescription = stringRes(R.string.use_direct_url),
+ contentDescription = stringResource(Res.string.use_direct_url),
modifier = Modifier.size(20.dp),
)
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/EditNicknameDialog.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip85TrustedAssertions/ui/EditNicknameDialog.kt
similarity index 55%
rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/EditNicknameDialog.kt
rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip85TrustedAssertions/ui/EditNicknameDialog.kt
index 54f1a469a3..b24c98cbb5 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/EditNicknameDialog.kt
+++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip85TrustedAssertions/ui/EditNicknameDialog.kt
@@ -18,35 +18,41 @@
* 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.screen.loggedIn.profile.header
+package com.vitorpamplona.amethyst.commons.nip85TrustedAssertions.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
-import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.commons.model.User
import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState
+import com.vitorpamplona.amethyst.commons.model.nip85TrustedAssertions.ContactCardsState
+import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
+import com.vitorpamplona.amethyst.commons.resources.Res
+import com.vitorpamplona.amethyst.commons.resources.nickname_cancel
+import com.vitorpamplona.amethyst.commons.resources.nickname_dialog_explainer
+import com.vitorpamplona.amethyst.commons.resources.nickname_dialog_title
+import com.vitorpamplona.amethyst.commons.resources.nickname_label
+import com.vitorpamplona.amethyst.commons.resources.nickname_save
+import com.vitorpamplona.amethyst.commons.resources.nickname_summary_label
import com.vitorpamplona.amethyst.commons.ui.text.currentWord
-import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord
-import com.vitorpamplona.amethyst.model.User
-import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
-import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
-import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
-import com.vitorpamplona.amethyst.ui.stringRes
-import com.vitorpamplona.amethyst.ui.theme.placeholderText
+import kotlinx.coroutines.launch
+import org.jetbrains.compose.resources.stringResource
/**
* Edits the nickname (petname) and private note (summary) the account keeps for
@@ -55,79 +61,82 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText
*
* Typing `:` offers the account's NIP-30 custom emojis; the mappings for any
* shortcode used are embedded (also encrypted) so the nickname renders with them.
+ *
+ * Shared by every front end: the caller supplies the account's [contactCards]
+ * and publishes the result in [onSave] (e.g. through its outbox relays). On
+ * Android, compose `WatchAndLoadMyEmojiList` alongside so the emoji packs load.
*/
@Composable
fun EditNicknameDialog(
user: User,
+ contactCards: ContactCardsState,
+ onSave: (petName: String?, summary: String?) -> Unit,
onDismiss: () -> Unit,
- accountViewModel: AccountViewModel,
) {
val nickname = rememberTextFieldState()
val summary = rememberTextFieldState()
- val emojiSuggestions = remember(accountViewModel) { EmojiSuggestionState(accountViewModel.account.emoji) }
- // which field the emoji autocomplete should insert into
+ val emojiSuggestions = remember(contactCards) { EmojiSuggestionState(contactCards.emojiPacks) }
+ // which field the emoji autocomplete should insert into: the last one edited
val emojiTarget = remember { mutableStateOf(null) }
- // keeps the account's selected emoji packs loaded while the dialog is open
- WatchAndLoadMyEmojiList(accountViewModel)
-
// Prefill with the card's current encrypted values, if any. Decryption can
// be slow on external signers, so don't clobber anything already typed.
LaunchedEffect(user) {
- accountViewModel.account.contactCards
+ contactCards
.petName(user.pubkeyHex)
?.takeIf { nickname.text.isEmpty() }
?.let { nickname.setTextAndPlaceCursorAtEnd(it) }
- accountViewModel.account.contactCards
+ contactCards
.summary(user.pubkeyHex)
?.takeIf { summary.text.isEmpty() }
?.let { summary.setTextAndPlaceCursorAtEnd(it) }
}
- fun watchEmojiIn(field: TextFieldState) {
- emojiTarget.value = field
- if (field.selection.collapsed) {
- emojiSuggestions.processCurrentWord(field.currentWord())
+ // Feed the word under the cursor of the last-edited field to the autocomplete.
+ LaunchedEffect(nickname, summary) {
+ fun watch(field: TextFieldState) {
+ emojiTarget.value = field
+ if (field.selection.collapsed) {
+ emojiSuggestions.processCurrentWord(field.currentWord())
+ }
}
+ launch { snapshotFlow { nickname.text }.collect { watch(nickname) } }
+ launch { snapshotFlow { summary.text }.collect { watch(summary) } }
}
AlertDialog(
onDismissRequest = onDismiss,
title = {
- Text(text = stringRes(R.string.nickname_dialog_title))
+ Text(text = stringResource(Res.string.nickname_dialog_title))
},
text = {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
) {
Text(
- text = stringRes(R.string.nickname_dialog_explainer),
- color = MaterialTheme.colorScheme.placeholderText,
+ text = stringResource(Res.string.nickname_dialog_explainer),
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
)
- ThinPaddingTextField(
+ OutlinedTextField(
state = nickname,
- onTextChanged = { watchEmojiIn(nickname) },
- singleLine = true,
+ lineLimits = TextFieldLineLimits.SingleLine,
label = {
- Text(text = stringRes(R.string.nickname_label))
+ Text(text = stringResource(Res.string.nickname_label))
},
)
- ThinPaddingTextField(
+ OutlinedTextField(
state = summary,
- onTextChanged = { watchEmojiIn(summary) },
label = {
- Text(text = stringRes(R.string.nickname_summary_label))
+ Text(text = stringResource(Res.string.nickname_summary_label))
},
)
ShowEmojiSuggestionList(
emojiSuggestions,
- onSelect = {
- emojiTarget.value?.replaceCurrentWord(":${it.code}:")
- emojiSuggestions.reset()
+ onSelect = { emoji ->
+ emojiTarget.value?.let { emojiSuggestions.autocompleteInto(it, emoji) }
},
- onFullSize = {
- emojiTarget.value?.replaceCurrentWord(":${it.code}:")
- emojiSuggestions.reset()
+ onFullSize = { emoji ->
+ emojiTarget.value?.let { emojiSuggestions.autocompleteInto(it, emoji) }
},
modifier = Modifier.heightIn(max = 200.dp),
)
@@ -136,30 +145,27 @@ fun EditNicknameDialog(
confirmButton = {
Button(
onClick = {
- accountViewModel.updateContactCardPetName(
- user = user,
- petName =
- nickname.text
- .toString()
- .trim()
- .ifBlank { null },
- summary =
- summary.text
- .toString()
- .trim()
- .ifBlank { null },
+ onSave(
+ nickname.text
+ .toString()
+ .trim()
+ .ifBlank { null },
+ summary.text
+ .toString()
+ .trim()
+ .ifBlank { null },
)
onDismiss()
},
) {
- Text(stringRes(R.string.save))
+ Text(stringResource(Res.string.nickname_save))
}
},
dismissButton = {
Button(
onClick = onDismiss,
) {
- Text(stringRes(R.string.cancel))
+ Text(stringResource(Res.string.nickname_cancel))
}
},
)
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/FilterContactCardsToKey.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/assemblers/ContactCardFilters.kt
similarity index 69%
rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/FilterContactCardsToKey.kt
rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/assemblers/ContactCardFilters.kt
index 8013013f99..f75e6819f2 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/FilterContactCardsToKey.kt
+++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/assemblers/ContactCardFilters.kt
@@ -18,7 +18,7 @@
* 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.service.relayClient.reqCommand.user.watchers
+package com.vitorpamplona.amethyst.commons.relayClient.assemblers
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter
@@ -28,6 +28,11 @@ import com.vitorpamplona.quartz.nip85TrustedAssertions.users.ContactCardEvent
val ContactCardKindList = listOf(ContactCardEvent.KIND)
+/**
+ * Kind:30382 cards *about* [targets], written by [trustedAccounts] (the account
+ * itself plus its WoT trust providers). Fetches nicknames and scores for the
+ * users currently on screen.
+ */
fun filterContactCardsToTargetKeysFromTrustedAccountsInTheRelay(
targets: Set,
trustedAccounts: List,
@@ -46,3 +51,25 @@ fun filterContactCardsToTargetKeysFromTrustedAccountsInTheRelay(
),
)
}
+
+/**
+ * Every kind:30382 card *written by* [author] — the account's own nicknames —
+ * for the bulk download at login from the account's relays. Addressable events:
+ * one card per target user, hence the larger limit.
+ */
+fun filterContactCardsByAuthorInTheRelay(
+ relay: NormalizedRelayUrl,
+ author: HexKey,
+ since: Long?,
+ limit: Int = 500,
+): RelayBasedFilter =
+ RelayBasedFilter(
+ relay = relay,
+ filter =
+ Filter(
+ kinds = ContactCardKindList,
+ authors = listOf(author),
+ limit = limit,
+ since = since,
+ ),
+ )