diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index ba7c5b719..23ec04639 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -94,6 +94,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessGameScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessLobbyScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.CommunityScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.list.CommunitiesScreen +import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.newCommunity.EditCommunityScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.newCommunity.NewCommunityScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.DiscoverScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm.LongFormPostScreen @@ -225,6 +226,7 @@ fun BuildNavigation( composableFromEnd { PollsScreen(accountViewModel, nav) } composableFromEnd { CommunitiesScreen(accountViewModel, nav) } composableFromEnd { NewCommunityScreen(accountViewModel, nav) } + composableFromEndArgs { EditCommunityScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) } composableFromEnd { BadgesScreen(accountViewModel, nav) } composableFromEnd { ProfileBadgesScreen(accountViewModel, nav) } composableFromBottomArgs { AwardBadgeScreen(it.kind, it.pubKeyHex, it.dTag, accountViewModel, nav) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/Routes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/Routes.kt index 721b1e957..53d08be4b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/Routes.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/Routes.kt @@ -49,6 +49,18 @@ sealed class Route { @Serializable object NewCommunity : Route() + @Serializable data class EditCommunity( + val kind: Int, + val pubKeyHex: HexKey, + val dTag: String, + ) : Route() { + constructor(address: Address) : this( + kind = address.kind, + pubKeyHex = address.pubKeyHex, + dTag = address.dTag, + ) + } + @Serializable object Badges : Route() @Serializable object ProfileBadges : Route() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/FeedFilterSpinner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/FeedFilterSpinner.kt index cc178d3e6..dc2c775bd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/FeedFilterSpinner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/FeedFilterSpinner.kt @@ -104,6 +104,7 @@ import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent +import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import kotlinx.collections.immutable.ImmutableList @@ -351,7 +352,10 @@ fun RenderOption( is CommunityName -> { val it by observeNote(option.note, accountViewModel) - Text(text = "/n/${((it.note as? AddressableNote)?.dTag() ?: "")}", fontSize = Font14SP, color = MaterialTheme.colorScheme.onSurface) + val addressable = it.note as? AddressableNote + val definition = addressable?.event as? CommunityDefinitionEvent + val label = definition?.name()?.ifBlank { null } ?: addressable?.dTag() ?: "" + Text(text = "/n/$label", fontSize = Font14SP, color = MaterialTheme.colorScheme.onSurface) } is RelayName -> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt index 68f928f2c..0ece66d12 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt @@ -24,9 +24,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.text.style.TextOverflow +import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote import com.vitorpamplona.amethyst.ui.components.ClickableTextColor import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -34,6 +37,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.HalfStartPadding import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip72ModCommunities.communityAddress +import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent @Composable fun DisplayFollowingCommunityInPost( @@ -42,38 +46,46 @@ fun DisplayFollowingCommunityInPost( nav: INav, ) { Column(HalfStartPadding) { - Row(verticalAlignment = Alignment.CenterVertically) { DisplayCommunity(baseNote, nav) } + Row(verticalAlignment = Alignment.CenterVertically) { DisplayCommunity(baseNote, accountViewModel, nav) } } } @Composable private fun DisplayCommunity( note: Note, + accountViewModel: AccountViewModel, nav: INav, ) { val communityTag = note.event?.communityAddress() ?: return + val communityNote = LocalCache.getOrCreateAddressableNote(communityTag) + val communityState by observeNote(communityNote, accountViewModel) + val label = communityShortLabel(communityTag, communityState.note.event as? CommunityDefinitionEvent) + ClickableTextColor( - getCommunityShortName(communityTag), + label, linkColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.52f), overflow = TextOverflow.Ellipsis, maxLines = 1, ) { nav.nav { - note.event?.communityAddress()?.let { communityTag -> - Route.Community(communityTag.kind, communityTag.pubKeyHex, communityTag.dTag) + note.event?.communityAddress()?.let { addr -> + Route.Community(addr.kind, addr.pubKeyHex, addr.dTag) } } } } -fun getCommunityShortName(communityAddress: Address): String { - val name = - if (communityAddress.dTag.length > 10) { - communityAddress.dTag.take(10) + "..." +private fun communityShortLabel( + address: Address, + definition: CommunityDefinitionEvent?, +): String { + val raw = definition?.name()?.ifBlank { null } ?: address.dTag + val shortened = + if (raw.length > 12) { + raw.take(12) + "..." } else { - communityAddress.dTag.take(10) + raw } - - return "/n/$name" + return "/n/$shortened" } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt index 81725b40a..f61ddf1df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt @@ -34,6 +34,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Share +import androidx.compose.material.icons.outlined.Edit import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.FilledTonalButton @@ -70,6 +71,7 @@ import com.vitorpamplona.amethyst.ui.components.RichTextViewer import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.note.LikeReaction @@ -439,6 +441,9 @@ private fun LongCommunityActionOptions( nav: INav, ) { Row { + if (note.author?.pubkeyHex == accountViewModel.account.signer.pubKey) { + EditCommunityButton(note, nav) + } ShareCommunityButton(accountViewModel, note, nav) WatchAddressableNoteFollows(note, accountViewModel) { isFollowing -> if (isFollowing) { @@ -448,6 +453,22 @@ private fun LongCommunityActionOptions( } } +@Composable +fun EditCommunityButton( + note: AddressableNote, + nav: INav, +) { + FilledTonalIconButton( + onClick = { nav.nav(Route.EditCommunity(note.address)) }, + ) { + Icon( + imageVector = Icons.Outlined.Edit, + modifier = Size18Modifier, + contentDescription = stringRes(R.string.edit_community), + ) + } +} + @Composable fun WatchAddressableNoteFollows( note: AddressableNote, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt index 81cd62793..7c502ce92 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt @@ -36,6 +36,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent import com.vitorpamplona.quartz.nip51Lists.interestSet.InterestSetEvent import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent +import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.persistentListOf @@ -381,7 +382,11 @@ class PeopleListName( class CommunityName( val note: AddressableNote, ) : Name() { - override fun name() = "/n/${(note.dTag())}" + override fun name(): String { + val definition = note.event as? CommunityDefinitionEvent + val label = definition?.name()?.ifBlank { null } ?: note.dTag() + return "/n/$label" + } } @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt index 2e480fb5c..09c61bed8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt @@ -43,6 +43,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions +import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.ModeratorTag import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.RelayTag import kotlinx.collections.immutable.ImmutableList @@ -61,11 +62,16 @@ data class CommunityRelayEntry( class NewCommunityModel : ViewModel() { var account: Account? = null + // When set, publish() reuses this d-tag so the kind-34550 replaceable event + // is updated in place (edit flow). Null in the create flow. + var existingDTag: String? = null + var isPublishing by mutableStateOf(false) var name by mutableStateOf("") var description by mutableStateOf("") var rules by mutableStateOf("") + var existingImageUrl by mutableStateOf(null) // Image upload state - mirrors NewBadgeModel. var multiOrchestrator by mutableStateOf(null) @@ -88,6 +94,42 @@ class NewCommunityModel : ViewModel() { this.stripMetadata = account.settings.stripLocationOnUpload } + /** + * Preloads the form with the current contents of [existing] so the user can edit + * the replaceable kind 34550 event. Keeps the original `d` tag so relays replace + * the previous version instead of creating a new community. + */ + fun loadFrom(existing: CommunityDefinitionEvent) { + existingDTag = existing.dTag() + name = existing.name().orEmpty() + description = existing.description().orEmpty() + rules = existing.rules().orEmpty() + existingImageUrl = existing.image()?.imageUrl + + val ownerKey = account?.signer?.pubKey + moderators.clear() + existing + .moderatorKeys() + .asSequence() + .filter { it != ownerKey } + .distinct() + .forEach { pubkey -> + val user = account?.cache?.getOrCreateUser(pubkey) ?: return@forEach + if (moderators.none { it.pubkeyHex == user.pubkeyHex }) { + moderators.add(user) + } + } + + relays.clear() + existing.relays().forEach { tag -> + if (relays.none { it.url == tag.url }) { + relays.add(CommunityRelayEntry(tag.url, tag.marker)) + } + } + } + + fun isEditing(): Boolean = existingDTag != null + fun defaultServer() = account?.settings?.defaultFileServer ?: DEFAULT_MEDIA_SERVERS[0] fun setPickedMedia(uris: ImmutableList) { @@ -156,15 +198,15 @@ class NewCommunityModel : ViewModel() { viewModelScope.launch(Dispatchers.IO) { isPublishing = true try { - val imageUrl = - uploadImageIfAny(context, myAccount, onError) ?: run { - if (multiOrchestrator != null) { - // upload failed; error was reported, bail out - return@launch - } + val uploadedUrl = + if (multiOrchestrator != null) { + uploadImageIfAny(context, myAccount, onError) ?: return@launch + } else { null } + val imageUrl = uploadedUrl ?: existingImageUrl + val ownerKey = myAccount.signer.pubKey val moderatorTags = buildList { @@ -177,6 +219,8 @@ class NewCommunityModel : ViewModel() { val relayTags = relays.map { RelayTag(it.url, it.marker) } + val dTag = existingDTag ?: Uuid.random().toString() + val definition = myAccount.sendCommunityDefinition( name = name.trim(), @@ -185,7 +229,7 @@ class NewCommunityModel : ViewModel() { image = imageUrl, rules = rules.trim().ifBlank { null }, relays = relayTags.ifEmpty { null }, - dTag = Uuid.random().toString(), + dTag = dTag, ) if (definition == null) { @@ -196,9 +240,11 @@ class NewCommunityModel : ViewModel() { return@launch } - // Follow it so it shows up under "Mine". - val communityNote = myAccount.cache.getOrCreateAddressableNote(definition.address()) - myAccount.follow(communityNote) + // Auto-follow only on the create flow; editing doesn't change the follow set. + if (existingDTag == null) { + val communityNote = myAccount.cache.getOrCreateAddressableNote(definition.address()) + myAccount.follow(communityNote) + } selectedServer?.let { myAccount.settings.changeDefaultFileServer(it) } myAccount.settings.changeStripLocationOnUpload(stripMetadata) @@ -260,6 +306,8 @@ class NewCommunityModel : ViewModel() { name = "" description = "" rules = "" + existingImageUrl = null + existingDTag = null multiOrchestrator = null moderators.clear() relays.clear() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt index c68d871d7..bef4e8283 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt @@ -71,14 +71,17 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State +import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery import com.vitorpamplona.amethyst.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.ui.navigation.topbars.ActionTopBar import com.vitorpamplona.amethyst.ui.navigation.topbars.CreatingTopBar import com.vitorpamplona.amethyst.ui.note.UserPicture import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList @@ -89,14 +92,30 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditF import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.SuggestionListDefaultHeightPage +import com.vitorpamplona.quartz.nip01Core.core.Address +import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.RelayTag import kotlinx.collections.immutable.persistentListOf -@OptIn(ExperimentalMaterial3Api::class) @Composable fun NewCommunityScreen( accountViewModel: AccountViewModel, nav: INav, +) = CommunityFormScreen(editing = null, accountViewModel = accountViewModel, nav = nav) + +@Composable +fun EditCommunityScreen( + editing: Address, + accountViewModel: AccountViewModel, + nav: INav, +) = CommunityFormScreen(editing = editing, accountViewModel = accountViewModel, nav = nav) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun CommunityFormScreen( + editing: Address?, + accountViewModel: AccountViewModel, + nav: INav, ) { val model: NewCommunityModel = viewModel() val context = LocalContext.current @@ -105,6 +124,15 @@ fun NewCommunityScreen( model.init(accountViewModel.account) } + LaunchedEffect(editing) { + if (editing != null) { + val note = LocalCache.getOrCreateAddressableNote(editing) + (note.event as? CommunityDefinitionEvent)?.let { model.loadFrom(it) } + } else { + model.existingDTag = null + } + } + StrippingFailureDialog(model.strippingFailureConfirmation) var wantsToPickImage by remember { mutableStateOf(false) } @@ -122,21 +150,42 @@ fun NewCommunityScreen( Scaffold( topBar = { - CreatingTopBar( - titleRes = R.string.new_community, - isActive = model::canPost, - onCancel = { - model.reset() - nav.popBack() - }, - onPost = { - model.publish( - context = context, - onSuccess = { nav.popBack() }, - onError = accountViewModel.toastManager::toast, - ) - }, - ) + val titleRes = + if (model.isEditing()) R.string.edit_community else R.string.new_community + if (model.isEditing()) { + ActionTopBar( + titleRes = titleRes, + postRes = R.string.save, + isActive = model::canPost, + onCancel = { + model.reset() + nav.popBack() + }, + onPost = { + model.publish( + context = context, + onSuccess = { nav.popBack() }, + onError = accountViewModel.toastManager::toast, + ) + }, + ) + } else { + CreatingTopBar( + titleRes = titleRes, + isActive = model::canPost, + onCancel = { + model.reset() + nav.popBack() + }, + onPost = { + model.publish( + context = context, + onSuccess = { nav.popBack() }, + onError = accountViewModel.toastManager::toast, + ) + }, + ) + } }, ) { pad -> Surface( @@ -235,18 +284,69 @@ private fun CommunityImagePicker( accountViewModel: AccountViewModel, onPickImage: () -> Unit, ) { - if (model.hasPickedImage()) { - model.multiOrchestrator?.let { - Box(modifier = Modifier.clickable(onClick = onPickImage)) { - ShowImageUploadGallery( - list = it, - onDelete = { model.setPickedMedia(persistentListOf()) }, - accountViewModel = accountViewModel, - ) + val existingUrl = model.existingImageUrl + when { + model.hasPickedImage() -> { + model.multiOrchestrator?.let { + Box(modifier = Modifier.clickable(onClick = onPickImage)) { + ShowImageUploadGallery( + list = it, + onDelete = { model.setPickedMedia(persistentListOf()) }, + accountViewModel = accountViewModel, + ) + } } } - } else { - CommunityImagePlaceholder(onClick = onPickImage) + + !existingUrl.isNullOrBlank() -> { + ExistingCommunityCover( + url = existingUrl, + onClick = onPickImage, + onClear = { model.existingImageUrl = null }, + ) + } + + else -> { + CommunityImagePlaceholder(onClick = onPickImage) + } + } +} + +@Composable +private fun ExistingCommunityCover( + url: String, + onClick: () -> Unit, + onClear: () -> Unit, +) { + Box( + modifier = + Modifier + .fillMaxWidth() + .aspectRatio(16f / 9f) + .clickable(onClick = onClick), + contentAlignment = Alignment.TopEnd, + ) { + AsyncImage( + model = url, + contentDescription = null, + contentScale = androidx.compose.ui.layout.ContentScale.Crop, + modifier = + Modifier + .fillMaxWidth() + .aspectRatio(16f / 9f) + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outline, + shape = RoundedCornerShape(16.dp), + ), + ) + IconButton(onClick = onClear) { + Icon( + imageVector = Icons.Outlined.Close, + contentDescription = stringRes(R.string.remove), + tint = MaterialTheme.colorScheme.onSurface, + ) + } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt index fe246d8b6..266d8f9ba 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt @@ -96,7 +96,7 @@ fun RenderCommunitiesThumb( RenderCommunitiesThumb( CommunityCard( - name = noteEvent.dTag(), + name = noteEvent.name()?.ifBlank { null } ?: noteEvent.dTag(), description = noteEvent.description(), cover = noteEvent.image()?.imageUrl, moderators = noteEvent.moderatorKeys().toImmutableList(), diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 7474e1f40..51e4f0fab 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -422,6 +422,7 @@ Badges Communities New Community + Edit Community Community name Description Rules (optional)