mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-29 21:52:31 +02:00
Moves chatroom user group away from immutable sets
This commit is contained in:
@@ -52,7 +52,7 @@ object NostrChatroomDataSource : NostrDataSource("ChatroomFeed") {
|
|||||||
filter =
|
filter =
|
||||||
JsonFilter(
|
JsonFilter(
|
||||||
kinds = listOf(PrivateDmEvent.KIND),
|
kinds = listOf(PrivateDmEvent.KIND),
|
||||||
authors = myPeer.users.map { it },
|
authors = myPeer.users.toList(),
|
||||||
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
|
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
|
||||||
since =
|
since =
|
||||||
latestEOSEs.users[account.userProfile()]
|
latestEOSEs.users[account.userProfile()]
|
||||||
@@ -103,7 +103,6 @@ object NostrChatroomDataSource : NostrDataSource("ChatroomFeed") {
|
|||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
createMessagesToMeFilter(),
|
createMessagesToMeFilter(),
|
||||||
createMessagesFromMeFilter(),
|
createMessagesFromMeFilter(),
|
||||||
)
|
).ifEmpty { null }
|
||||||
.ifEmpty { null }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -167,7 +167,12 @@ fun AppTopBar(
|
|||||||
) {
|
) {
|
||||||
val currentRoute by
|
val currentRoute by
|
||||||
remember(navEntryState.value) {
|
remember(navEntryState.value) {
|
||||||
derivedStateOf { navEntryState.value?.destination?.route?.substringBefore("?") }
|
derivedStateOf {
|
||||||
|
navEntryState.value
|
||||||
|
?.destination
|
||||||
|
?.route
|
||||||
|
?.substringBefore("?")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val id by
|
val id by
|
||||||
@@ -397,7 +402,7 @@ private fun RenderRoomTopBar(
|
|||||||
FlexibleTopBarWithBackButton(
|
FlexibleTopBarWithBackButton(
|
||||||
title = {
|
title = {
|
||||||
NonClickableUserPictures(
|
NonClickableUserPictures(
|
||||||
users = room.users,
|
room = room,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
size = Size34dp,
|
size = Size34dp,
|
||||||
)
|
)
|
||||||
@@ -577,7 +582,11 @@ private fun LoggedInUserPictureDrawer(
|
|||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val profilePicture by
|
val profilePicture by
|
||||||
accountViewModel.account.userProfile().live().profilePictureChanges.observeAsState()
|
accountViewModel.account
|
||||||
|
.userProfile()
|
||||||
|
.live()
|
||||||
|
.profilePictureChanges
|
||||||
|
.observeAsState()
|
||||||
|
|
||||||
IconButton(onClick = onClick) {
|
IconButton(onClick = onClick) {
|
||||||
RobohashFallbackAsyncImage(
|
RobohashFallbackAsyncImage(
|
||||||
@@ -633,32 +642,48 @@ abstract class Name {
|
|||||||
open fun name(context: Context) = name()
|
open fun name(context: Context) = name()
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeoHashName(val geoHashTag: String) : Name() {
|
class GeoHashName(
|
||||||
|
val geoHashTag: String,
|
||||||
|
) : Name() {
|
||||||
override fun name() = "/g/$geoHashTag"
|
override fun name() = "/g/$geoHashTag"
|
||||||
}
|
}
|
||||||
|
|
||||||
class HashtagName(val hashTag: String) : Name() {
|
class HashtagName(
|
||||||
|
val hashTag: String,
|
||||||
|
) : Name() {
|
||||||
override fun name() = "#$hashTag"
|
override fun name() = "#$hashTag"
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceName(val resourceId: Int) : Name() {
|
class ResourceName(
|
||||||
|
val resourceId: Int,
|
||||||
|
) : Name() {
|
||||||
override fun name() = " $resourceId " // Space to make sure it goes first
|
override fun name() = " $resourceId " // Space to make sure it goes first
|
||||||
|
|
||||||
override fun name(context: Context) = context.getString(resourceId)
|
override fun name(context: Context) = context.getString(resourceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PeopleListName(val note: AddressableNote) : Name() {
|
class PeopleListName(
|
||||||
|
val note: AddressableNote,
|
||||||
|
) : Name() {
|
||||||
override fun name() = (note.event as? PeopleListEvent)?.nameOrTitle() ?: note.dTag() ?: ""
|
override fun name() = (note.event as? PeopleListEvent)?.nameOrTitle() ?: note.dTag() ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
class CommunityName(val note: AddressableNote) : Name() {
|
class CommunityName(
|
||||||
|
val note: AddressableNote,
|
||||||
|
) : Name() {
|
||||||
override fun name() = "/n/${(note.dTag() ?: "")}"
|
override fun name() = "/n/${(note.dTag() ?: "")}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable data class CodeName(val code: String, val name: Name, val type: CodeNameType)
|
@Immutable data class CodeName(
|
||||||
|
val code: String,
|
||||||
|
val name: Name,
|
||||||
|
val type: CodeNameType,
|
||||||
|
)
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class FollowListViewModel(val account: Account) : ViewModel() {
|
class FollowListViewModel(
|
||||||
|
val account: Account,
|
||||||
|
) : ViewModel() {
|
||||||
val kind3Follow =
|
val kind3Follow =
|
||||||
CodeName(KIND3_FOLLOWS, ResourceName(R.string.follow_list_kind3follows), CodeNameType.HARDCODED)
|
CodeName(KIND3_FOLLOWS, ResourceName(R.string.follow_list_kind3follows), CodeNameType.HARDCODED)
|
||||||
val globalFollow =
|
val globalFollow =
|
||||||
@@ -699,8 +724,7 @@ class FollowListViewModel(val account: Account) : ViewModel() {
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}.sortedBy { it.name.name() }
|
||||||
.sortedBy { it.name.name() }
|
|
||||||
|
|
||||||
emit(newFollowLists)
|
emit(newFollowLists)
|
||||||
}
|
}
|
||||||
@@ -757,10 +781,10 @@ class FollowListViewModel(val account: Account) : ViewModel() {
|
|||||||
|
|
||||||
val kind3GlobalPeople = _kind3GlobalPeople.stateIn(viewModelScope, SharingStarted.Eagerly, defaultLists)
|
val kind3GlobalPeople = _kind3GlobalPeople.stateIn(viewModelScope, SharingStarted.Eagerly, defaultLists)
|
||||||
|
|
||||||
class Factory(val account: Account) : ViewModelProvider.Factory {
|
class Factory(
|
||||||
override fun <FollowListViewModel : ViewModel> create(modelClass: Class<FollowListViewModel>): FollowListViewModel {
|
val account: Account,
|
||||||
return FollowListViewModel(account) as FollowListViewModel
|
) : ViewModelProvider.Factory {
|
||||||
}
|
override fun <FollowListViewModel : ViewModel> create(modelClass: Class<FollowListViewModel>): FollowListViewModel = FollowListViewModel(account) as FollowListViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +966,8 @@ fun AmethystClickableIcon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun debugState(context: Context) {
|
fun debugState(context: Context) {
|
||||||
Client.allSubscriptions()
|
Client
|
||||||
|
.allSubscriptions()
|
||||||
.forEach { Log.d("STATE DUMP", "${it.key} ${it.value.joinToString { it.filter.toJson() }}") }
|
.forEach { Log.d("STATE DUMP", "${it.key} ${it.value.joinToString { it.filter.toJson() }}") }
|
||||||
|
|
||||||
NostrAccountDataSource.printCounter()
|
NostrAccountDataSource.printCounter()
|
||||||
|
@@ -164,7 +164,10 @@ private fun ChannelRoomCompose(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val authorState by note.author!!.live().metadata.observeAsState()
|
val authorState by note.author!!
|
||||||
|
.live()
|
||||||
|
.metadata
|
||||||
|
.observeAsState()
|
||||||
val authorName = remember(note, authorState) { authorState?.user?.toBestDisplayName() }
|
val authorName = remember(note, authorState) { authorState?.user?.toBestDisplayName() }
|
||||||
|
|
||||||
val chanHex = remember { channel.idHex }
|
val chanHex = remember { channel.idHex }
|
||||||
@@ -273,7 +276,7 @@ private fun UserRoomCompose(
|
|||||||
ChannelName(
|
ChannelName(
|
||||||
channelPicture = {
|
channelPicture = {
|
||||||
NonClickableUserPictures(
|
NonClickableUserPictures(
|
||||||
users = room.users,
|
room = room,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
size = Size55dp,
|
size = Size55dp,
|
||||||
)
|
)
|
||||||
@@ -536,7 +539,8 @@ private fun TimeAgo(channelLastTime: Long?) {
|
|||||||
fun NewItemsBubble() {
|
fun NewItemsBubble() {
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.padding(start = 3.dp)
|
Modifier
|
||||||
|
.padding(start = 3.dp)
|
||||||
.width(10.dp)
|
.width(10.dp)
|
||||||
.height(10.dp)
|
.height(10.dp)
|
||||||
.clip(shape = CircleShape)
|
.clip(shape = CircleShape)
|
||||||
|
@@ -50,8 +50,7 @@ import com.vitorpamplona.amethyst.model.User
|
|||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.events.ChatroomKey
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NoteAuthorPicture(
|
fun NoteAuthorPicture(
|
||||||
@@ -157,14 +156,16 @@ fun ClickableUserPicture(
|
|||||||
val myModifier =
|
val myModifier =
|
||||||
remember {
|
remember {
|
||||||
if (onClick != null && onLongClick != null) {
|
if (onClick != null && onLongClick != null) {
|
||||||
Modifier.size(size)
|
Modifier
|
||||||
|
.size(size)
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = { onClick(baseUser) },
|
onClick = { onClick(baseUser) },
|
||||||
onLongClick = { onLongClick(baseUser) },
|
onLongClick = { onLongClick(baseUser) },
|
||||||
role = Role.Button,
|
role = Role.Button,
|
||||||
)
|
)
|
||||||
} else if (onClick != null) {
|
} else if (onClick != null) {
|
||||||
Modifier.size(size)
|
Modifier
|
||||||
|
.size(size)
|
||||||
.clickable(
|
.clickable(
|
||||||
onClick = { onClick(baseUser) },
|
onClick = { onClick(baseUser) },
|
||||||
role = Role.Button,
|
role = Role.Button,
|
||||||
@@ -181,15 +182,13 @@ fun ClickableUserPicture(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NonClickableUserPictures(
|
fun NonClickableUserPictures(
|
||||||
users: ImmutableSet<HexKey>,
|
room: ChatroomKey,
|
||||||
size: Dp,
|
size: Dp,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
) {
|
) {
|
||||||
val myBoxModifier = remember { Modifier.size(size) }
|
val userList = remember(room) { room.users.toList() }
|
||||||
|
|
||||||
Box(myBoxModifier, contentAlignment = Alignment.TopEnd) {
|
|
||||||
val userList = remember(users) { users.toList() }
|
|
||||||
|
|
||||||
|
Box(Modifier.size(size), contentAlignment = Alignment.TopEnd) {
|
||||||
when (userList.size) {
|
when (userList.size) {
|
||||||
0 -> {}
|
0 -> {}
|
||||||
1 ->
|
1 ->
|
||||||
@@ -395,13 +394,11 @@ fun WatchUserFollows(
|
|||||||
.map {
|
.map {
|
||||||
it.user.isFollowingCached(userHex) ||
|
it.user.isFollowingCached(userHex) ||
|
||||||
(userHex == accountViewModel.account.userProfile().pubkeyHex)
|
(userHex == accountViewModel.account.userProfile().pubkeyHex)
|
||||||
}
|
}.distinctUntilChanged()
|
||||||
.distinctUntilChanged()
|
}.observeAsState(
|
||||||
}
|
accountViewModel.account.userProfile().isFollowingCached(userHex) ||
|
||||||
.observeAsState(
|
(userHex == accountViewModel.account.userProfile().pubkeyHex),
|
||||||
accountViewModel.account.userProfile().isFollowingCached(userHex) ||
|
)
|
||||||
(userHex == accountViewModel.account.userProfile().pubkeyHex),
|
|
||||||
)
|
|
||||||
|
|
||||||
onFollowChanges(showFollowingMark)
|
onFollowChanges(showFollowingMark)
|
||||||
}
|
}
|
||||||
|
@@ -672,7 +672,7 @@ fun GroupChatroomHeader(
|
|||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
NonClickableUserPictures(
|
NonClickableUserPictures(
|
||||||
users = room.users,
|
room = room,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
size = Size34dp,
|
size = Size34dp,
|
||||||
)
|
)
|
||||||
|
@@ -26,7 +26,6 @@ import com.vitorpamplona.quartz.encoders.HexKey
|
|||||||
import com.vitorpamplona.quartz.encoders.Nip92MediaAttachments
|
import com.vitorpamplona.quartz.encoders.Nip92MediaAttachments
|
||||||
import com.vitorpamplona.quartz.signers.NostrSigner
|
import com.vitorpamplona.quartz.signers.NostrSigner
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
|
||||||
import kotlinx.collections.immutable.toImmutableSet
|
import kotlinx.collections.immutable.toImmutableSet
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -37,7 +36,8 @@ class ChatMessageEvent(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : WrappedEvent(id, pubKey, createdAt, KIND, tags, content, sig), ChatroomKeyable {
|
) : WrappedEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||||
|
ChatroomKeyable {
|
||||||
/** Recipients intended to receive this conversation */
|
/** Recipients intended to receive this conversation */
|
||||||
fun recipientsPubKey() = tags.mapNotNull { if (it.size > 1 && it[0] == "p") it[1] else null }
|
fun recipientsPubKey() = tags.mapNotNull { if (it.size > 1 && it[0] == "p") it[1] else null }
|
||||||
|
|
||||||
@@ -61,9 +61,7 @@ class ChatMessageEvent(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chatroomKey(toRemove: String): ChatroomKey {
|
override fun chatroomKey(toRemove: String): ChatroomKey = ChatroomKey(talkingWith(toRemove).toImmutableSet())
|
||||||
return ChatroomKey(talkingWith(toRemove).toImmutableSet())
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KIND = 14
|
const val KIND = 14
|
||||||
@@ -122,5 +120,5 @@ interface ChatroomKeyable {
|
|||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class ChatroomKey(
|
data class ChatroomKey(
|
||||||
val users: ImmutableSet<HexKey>,
|
val users: Set<HexKey>,
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user