mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-26 17:52:29 +01:00
Moving observable classes to the leaf nodes.
This commit is contained in:
parent
b3ce10c2de
commit
fb73308995
@ -369,7 +369,7 @@ class Account(
|
||||
}
|
||||
}
|
||||
|
||||
fun isHidden(user: User) = user !in hiddenUsers()
|
||||
fun isHidden(user: User) = user in hiddenUsers()
|
||||
|
||||
fun isAcceptable(user: User): Boolean {
|
||||
return user !in hiddenUsers() // if user hasn't hided this author
|
||||
|
@ -72,8 +72,6 @@ object LocalCache {
|
||||
// new event
|
||||
val oldUser = getOrCreateUser(event.pubKey.toHexKey())
|
||||
if (event.createdAt > oldUser.updatedMetadataAt) {
|
||||
//Log.d("MT", "New User ${users.size} ${event.contactMetaData.name}")
|
||||
|
||||
val newUser = try {
|
||||
metadataParser.readValue<UserMetadata>(ByteArrayInputStream(event.content.toByteArray(Charsets.UTF_8)), UserMetadata::class.java)
|
||||
} catch (e: Exception) {
|
||||
@ -84,6 +82,8 @@ object LocalCache {
|
||||
|
||||
oldUser.updateUserInfo(newUser, event.createdAt)
|
||||
oldUser.latestMetadata = event
|
||||
|
||||
//Log.d("MT", "New User Metadata ${oldUser.pubkeyDisplayHex} ${oldUser.toBestDisplayName()}")
|
||||
} else {
|
||||
//Log.d("MT","Relay sent a previous Metadata Event ${oldUser.toBestDisplayName()} ${formattedDateTime(event.createdAt)} > ${formattedDateTime(oldUser.updatedAt)}")
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ class Note(val idHex: String) {
|
||||
|
||||
var channel: Channel? = null
|
||||
|
||||
var lastDownloadTime: Long? = null
|
||||
|
||||
fun loadEvent(event: Event, author: User, mentions: List<User>, replyTo: MutableList<Note>) {
|
||||
this.event = event
|
||||
this.author = author
|
||||
@ -128,7 +130,7 @@ class Note(val idHex: String) {
|
||||
val returningList = mutableSetOf<User>()
|
||||
while (matcher.find()) {
|
||||
try {
|
||||
val tag = event?.tags?.get(matcher.group(1).toInt())
|
||||
val tag = matcher.group(1)?.let { event?.tags?.get(it.toInt()) }
|
||||
if (tag != null && tag[0] == "p") {
|
||||
returningList.add(LocalCache.getOrCreateUser(tag[1]))
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ class User(val pubkeyHex: String) {
|
||||
follows.add(user)
|
||||
user.followers.add(this)
|
||||
|
||||
invalidateData()
|
||||
user.invalidateData()
|
||||
invalidateData(liveFollows)
|
||||
user.invalidateData(liveFollows)
|
||||
|
||||
listeners.forEach {
|
||||
it.onFollowsChange()
|
||||
@ -75,8 +75,8 @@ class User(val pubkeyHex: String) {
|
||||
follows.remove(user)
|
||||
user.followers.remove(this)
|
||||
|
||||
invalidateData()
|
||||
user.invalidateData()
|
||||
invalidateData(liveFollows)
|
||||
user.invalidateData(liveFollows)
|
||||
|
||||
updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
@ -91,7 +91,7 @@ class User(val pubkeyHex: String) {
|
||||
fun addReport(note: Note) {
|
||||
if (reports.add(note)) {
|
||||
updateSubscribers { it.onNewReports() }
|
||||
invalidateData()
|
||||
invalidateData(liveReports)
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ class User(val pubkeyHex: String) {
|
||||
|
||||
fun addMessage(user: User, msg: Note) {
|
||||
getOrCreateChannel(user).add(msg)
|
||||
invalidateData()
|
||||
invalidateData(liveMessages)
|
||||
updateSubscribers { it.onNewMessage() }
|
||||
}
|
||||
|
||||
@ -140,6 +140,7 @@ class User(val pubkeyHex: String) {
|
||||
}
|
||||
|
||||
updateSubscribers { it.onNewRelayInfo() }
|
||||
invalidateData(liveRelayInfo)
|
||||
}
|
||||
|
||||
fun updateFollows(newFollows: Set<User>, updateAt: Long) {
|
||||
@ -167,15 +168,14 @@ class User(val pubkeyHex: String) {
|
||||
}
|
||||
}
|
||||
|
||||
invalidateData()
|
||||
invalidateData(liveRelays)
|
||||
}
|
||||
|
||||
fun updateUserInfo(newUserInfo: UserMetadata, updateAt: Long) {
|
||||
info = newUserInfo
|
||||
updatedMetadataAt = updateAt
|
||||
|
||||
|
||||
invalidateData()
|
||||
invalidateData(liveMetadata)
|
||||
}
|
||||
|
||||
fun isFollowing(user: User): Boolean {
|
||||
@ -242,16 +242,21 @@ class User(val pubkeyHex: String) {
|
||||
}
|
||||
|
||||
// UI Observers line up here.
|
||||
val live: UserLiveData = UserLiveData(this)
|
||||
val liveFollows: UserLiveData = UserLiveData(this)
|
||||
val liveReports: UserLiveData = UserLiveData(this)
|
||||
val liveMessages: UserLiveData = UserLiveData(this)
|
||||
val liveRelays: UserLiveData = UserLiveData(this)
|
||||
val liveRelayInfo: UserLiveData = UserLiveData(this)
|
||||
val liveMetadata: UserLiveData = UserLiveData(this)
|
||||
|
||||
// Refreshes observers in batches.
|
||||
var handlerWaiting = false
|
||||
@Synchronized
|
||||
fun invalidateData() {
|
||||
fun invalidateData(live: UserLiveData) {
|
||||
if (handlerWaiting) return
|
||||
|
||||
handlerWaiting = true
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
delay(100)
|
||||
live.refresh()
|
||||
|
@ -7,4 +7,9 @@ data class Channel (
|
||||
val id: String = UUID.randomUUID().toString().substring(0,4)
|
||||
) {
|
||||
var filter: List<JsonFilter>? = null // Inactive when null
|
||||
private var lastEOSE: Long? = null
|
||||
|
||||
fun updateEOSE(l: Long) {
|
||||
lastEOSE = l
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import com.vitorpamplona.amethyst.service.model.RepostEvent
|
||||
import com.vitorpamplona.amethyst.service.relays.Client
|
||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||
import java.util.Collections
|
||||
import java.util.Date
|
||||
import java.util.UUID
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTimedValue
|
||||
@ -90,7 +91,7 @@ abstract class NostrDataSource<T>(val debugName: String) {
|
||||
//Log.e("ERROR", "Relay ${relay.url}: ${error.message}")
|
||||
}
|
||||
|
||||
override fun onRelayStateChange(type: Relay.Type, relay: Relay) {
|
||||
override fun onRelayStateChange(type: Relay.Type, relay: Relay, channel: String?) {
|
||||
//Log.d("RELAY", "Relay ${relay.url} ${when (type) {
|
||||
// Relay.Type.CONNECT -> "connected."
|
||||
// Relay.Type.DISCONNECT -> "disconnected."
|
||||
@ -98,11 +99,10 @@ abstract class NostrDataSource<T>(val debugName: String) {
|
||||
// Relay.Type.EOSE -> "sent all events it had stored."
|
||||
//}}")
|
||||
|
||||
/*
|
||||
if (type == Relay.Type.EOSE) {
|
||||
// One everything is loaded, if new users are found, update filters
|
||||
resetFilters()
|
||||
}*/
|
||||
if (type == Relay.Type.EOSE && channel != null) {
|
||||
// updates a per subscripton since date
|
||||
channels.filter { it.id == channel }.firstOrNull()?.updateEOSE(Date().time / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSendResponse(eventId: String, success: Boolean, message: String, relay: Relay) {
|
||||
|
@ -14,7 +14,7 @@ object NostrSingleUserDataSource: NostrDataSource<User>("SingleUserFeed") {
|
||||
fun createUserFilter(): List<JsonFilter>? {
|
||||
if (usersToWatch.isEmpty()) return null
|
||||
|
||||
return usersToWatch.map {
|
||||
return usersToWatch.filter { LocalCache.getOrCreateUser(it).latestMetadata == null }.map {
|
||||
JsonFilter(
|
||||
kinds = listOf(MetadataEvent.kind),
|
||||
authors = listOf(it),
|
||||
|
@ -72,8 +72,8 @@ object Client: RelayPool.Listener {
|
||||
listeners.forEach { it.onError(error, subscriptionId, relay) }
|
||||
}
|
||||
|
||||
override fun onRelayStateChange(type: Relay.Type, relay: Relay) {
|
||||
listeners.forEach { it.onRelayStateChange(type, relay) }
|
||||
override fun onRelayStateChange(type: Relay.Type, relay: Relay, channel: String?) {
|
||||
listeners.forEach { it.onRelayStateChange(type, relay, channel) }
|
||||
}
|
||||
|
||||
override fun onSendResponse(eventId: String, success: Boolean, message: String, relay: Relay) {
|
||||
@ -112,7 +112,7 @@ object Client: RelayPool.Listener {
|
||||
/**
|
||||
* Connected to or disconnected from a relay
|
||||
*/
|
||||
open fun onRelayStateChange(type: Relay.Type, relay: Relay) = Unit
|
||||
open fun onRelayStateChange(type: Relay.Type, relay: Relay, channel: String?) = Unit
|
||||
|
||||
/**
|
||||
* When an relay saves or rejects a new event.
|
||||
|
@ -2,11 +2,8 @@ package com.vitorpamplona.amethyst.service.relays
|
||||
|
||||
import android.util.Log
|
||||
import com.google.gson.JsonElement
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import java.util.Date
|
||||
import nostr.postr.events.ContactListEvent
|
||||
import nostr.postr.events.Event
|
||||
import nostr.postr.toNpub
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
@ -50,7 +47,7 @@ class Relay(
|
||||
Client.allSubscriptions().forEach {
|
||||
sendFilter(requestId = it)
|
||||
}
|
||||
listeners.forEach { it.onRelayStateChange(this@Relay, Type.CONNECT) }
|
||||
listeners.forEach { it.onRelayStateChange(this@Relay, Type.CONNECT, null) }
|
||||
}
|
||||
|
||||
override fun onMessage(webSocket: WebSocket, text: String) {
|
||||
@ -65,7 +62,7 @@ class Relay(
|
||||
listeners.forEach { it.onEvent(this@Relay, channel, event) }
|
||||
}
|
||||
"EOSE" -> listeners.forEach {
|
||||
it.onRelayStateChange(this@Relay, Type.EOSE)
|
||||
it.onRelayStateChange(this@Relay, Type.EOSE, channel)
|
||||
}
|
||||
"NOTICE" -> listeners.forEach {
|
||||
// "channel" being the second string in the string array ...
|
||||
@ -91,13 +88,17 @@ class Relay(
|
||||
}
|
||||
|
||||
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
|
||||
listeners.forEach { it.onRelayStateChange(this@Relay, Type.DISCONNECTING) }
|
||||
listeners.forEach { it.onRelayStateChange(
|
||||
this@Relay,
|
||||
Type.DISCONNECTING,
|
||||
null
|
||||
) }
|
||||
}
|
||||
|
||||
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
||||
socket = null
|
||||
closingTime = Date().time / 1000
|
||||
listeners.forEach { it.onRelayStateChange(this@Relay, Type.DISCONNECT) }
|
||||
listeners.forEach { it.onRelayStateChange(this@Relay, Type.DISCONNECT, null) }
|
||||
}
|
||||
|
||||
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
||||
@ -192,6 +193,6 @@ class Relay(
|
||||
*
|
||||
* @param type is 0 for disconnect and 1 for connect
|
||||
*/
|
||||
fun onRelayStateChange(relay: Relay, type: Type)
|
||||
fun onRelayStateChange(relay: Relay, type: Type, channel: String?)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.vitorpamplona.amethyst.service.relays
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.vitorpamplona.amethyst.service.Constants
|
||||
import java.util.Collections
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@ -88,7 +87,7 @@ object RelayPool: Relay.Listener {
|
||||
|
||||
fun onError(error: Error, subscriptionId: String, relay: Relay)
|
||||
|
||||
fun onRelayStateChange(type: Relay.Type, relay: Relay)
|
||||
fun onRelayStateChange(type: Relay.Type, relay: Relay, channel: String?)
|
||||
|
||||
fun onSendResponse(eventId: String, success: Boolean, message: String, relay: Relay)
|
||||
}
|
||||
@ -103,8 +102,8 @@ object RelayPool: Relay.Listener {
|
||||
refreshObservers()
|
||||
}
|
||||
|
||||
override fun onRelayStateChange(relay: Relay, type: Relay.Type) {
|
||||
listeners.forEach { it.onRelayStateChange(type, relay) }
|
||||
override fun onRelayStateChange(relay: Relay, type: Relay.Type, channel: String?) {
|
||||
listeners.forEach { it.onRelayStateChange(type, relay, channel) }
|
||||
refreshObservers()
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,8 @@ fun ClickableRoute(
|
||||
) {
|
||||
if (nip19.type == Nip19.Type.USER) {
|
||||
val userBase = LocalCache.getOrCreateUser(nip19.hex)
|
||||
val userState by userBase.live.observeAsState()
|
||||
|
||||
val userState by userBase.liveMetadata.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
val route = "User/${nip19.hex}"
|
||||
|
@ -15,7 +15,7 @@ fun ClickableUserTag(
|
||||
user: User,
|
||||
navController: NavController
|
||||
) {
|
||||
val innerUserState by user.live.observeAsState()
|
||||
val innerUserState by user.liveMetadata.observeAsState()
|
||||
ClickableText(
|
||||
text = AnnotatedString("@${innerUserState?.user?.toBestDisplayName()} "),
|
||||
onClick = { navController.navigate("User/${innerUserState?.user?.pubkeyHex}") },
|
||||
|
@ -77,7 +77,7 @@ fun MainTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel)
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val accountUserState by account.userProfile().live.observeAsState()
|
||||
val accountUserState by account.userProfile().liveMetadata.observeAsState()
|
||||
val accountUser = accountUserState?.user
|
||||
|
||||
val relayViewModel: RelayPoolViewModel = viewModel { RelayPoolViewModel() }
|
||||
|
@ -81,52 +81,26 @@ fun DrawerContent(navController: NavHostController,
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val accountUserState by account.userProfile().live.observeAsState()
|
||||
val accountUser = accountUserState?.user ?: return
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = MaterialTheme.colors.background
|
||||
) {
|
||||
Column() {
|
||||
Box {
|
||||
val banner = accountUser?.info?.banner
|
||||
if (banner != null && banner.isNotBlank()) {
|
||||
AsyncImage(
|
||||
model = banner,
|
||||
contentDescription = "Profile Image",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(150.dp)
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.profile_banner),
|
||||
contentDescription = "Profile Banner",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(150.dp)
|
||||
)
|
||||
}
|
||||
|
||||
ProfileContent(
|
||||
accountUser,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 25.dp)
|
||||
.padding(top = 100.dp),
|
||||
scaffoldState,
|
||||
navController
|
||||
)
|
||||
}
|
||||
ProfileContent(
|
||||
account.userProfile(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 25.dp)
|
||||
.padding(top = 100.dp),
|
||||
scaffoldState,
|
||||
navController
|
||||
)
|
||||
Divider(
|
||||
thickness = 0.25.dp,
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
)
|
||||
ListContent(
|
||||
accountUser,
|
||||
account.userProfile(),
|
||||
navController,
|
||||
scaffoldState,
|
||||
modifier = Modifier
|
||||
@ -135,50 +109,79 @@ fun DrawerContent(navController: NavHostController,
|
||||
accountStateViewModel
|
||||
)
|
||||
|
||||
BottomContent(accountUser, scaffoldState, navController)
|
||||
BottomContent(account.userProfile(), scaffoldState, navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ProfileContent(accountUser: User?, modifier: Modifier = Modifier, scaffoldState: ScaffoldState, navController: NavController) {
|
||||
fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffoldState: ScaffoldState, navController: NavController) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
Column(modifier = modifier) {
|
||||
AsyncImage(
|
||||
model = accountUser?.profilePicture() ?: "https://robohash.org/ohno.png",
|
||||
contentDescription = "Profile Image",
|
||||
placeholder = rememberAsyncImagePainter("https://robohash.org/${accountUser?.pubkeyHex}.png"),
|
||||
modifier = Modifier
|
||||
.width(100.dp)
|
||||
.height(100.dp)
|
||||
.clip(shape = CircleShape)
|
||||
.border(3.dp, MaterialTheme.colors.background, CircleShape)
|
||||
.background(MaterialTheme.colors.background)
|
||||
.clickable(onClick = {
|
||||
accountUser?.let {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
}
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
})
|
||||
)
|
||||
Text(
|
||||
accountUser?.bestDisplayName() ?: "",
|
||||
modifier = Modifier.padding(top = 7.dp),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Text(" @${accountUser?.bestUsername()}", color = Color.LightGray)
|
||||
Row(modifier = Modifier.padding(top = 15.dp)) {
|
||||
Row() {
|
||||
Text("${accountUser?.follows?.size ?: "--"}", fontWeight = FontWeight.Bold)
|
||||
Text(" Following")
|
||||
}
|
||||
Row(modifier = Modifier.padding(start = 10.dp)) {
|
||||
Text("${accountUser?.followers?.size ?: "--"}", fontWeight = FontWeight.Bold)
|
||||
Text(" Followers")
|
||||
val accountUserState by baseAccountUser.liveMetadata.observeAsState()
|
||||
val accountUser = accountUserState?.user ?: return
|
||||
|
||||
val accountUserFollowsState by baseAccountUser.liveFollows.observeAsState()
|
||||
val accountUserFollows = accountUserFollowsState?.user ?: return
|
||||
|
||||
Box {
|
||||
val banner = accountUser.info.banner
|
||||
if (banner != null && banner.isNotBlank()) {
|
||||
AsyncImage(
|
||||
model = banner,
|
||||
contentDescription = "Profile Image",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(150.dp)
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.profile_banner),
|
||||
contentDescription = "Profile Banner",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(150.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Column(modifier = modifier) {
|
||||
AsyncImage(
|
||||
model = accountUser.profilePicture(),
|
||||
contentDescription = "Profile Image",
|
||||
placeholder = rememberAsyncImagePainter("https://robohash.org/${accountUser.pubkeyHex}.png"),
|
||||
modifier = Modifier
|
||||
.width(100.dp)
|
||||
.height(100.dp)
|
||||
.clip(shape = CircleShape)
|
||||
.border(3.dp, MaterialTheme.colors.background, CircleShape)
|
||||
.background(MaterialTheme.colors.background)
|
||||
.clickable(onClick = {
|
||||
accountUser.let {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
}
|
||||
coroutineScope.launch {
|
||||
scaffoldState.drawerState.close()
|
||||
}
|
||||
})
|
||||
)
|
||||
Text(
|
||||
accountUser.bestDisplayName() ?: "",
|
||||
modifier = Modifier.padding(top = 7.dp),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Text(" @${accountUser.bestUsername()}", color = Color.LightGray)
|
||||
Row(modifier = Modifier.padding(top = 15.dp)) {
|
||||
Row() {
|
||||
Text("${accountUserFollows.follows?.size ?: "--"}", fontWeight = FontWeight.Bold)
|
||||
Text(" Following")
|
||||
}
|
||||
Row(modifier = Modifier.padding(start = 10.dp)) {
|
||||
Text("${accountUserFollows.followers?.size ?: "--"}", fontWeight = FontWeight.Bold)
|
||||
Text(" Followers")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,9 +53,6 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val accountUserState by account.userProfile().live.observeAsState()
|
||||
val accountUser = accountUserState?.user ?: return
|
||||
|
||||
val notificationCacheState = NotificationCache.live.observeAsState()
|
||||
val notificationCache = notificationCacheState.value ?: return
|
||||
|
||||
@ -64,7 +61,7 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
|
||||
if (note?.event == null) {
|
||||
BlankNote(Modifier)
|
||||
} else if (note.channel != null) {
|
||||
val authorState by note.author!!.live.observeAsState()
|
||||
val authorState by note.author!!.liveMetadata.observeAsState()
|
||||
val author = authorState?.user
|
||||
|
||||
val channelState by note.channel!!.live.observeAsState()
|
||||
@ -108,25 +105,19 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
|
||||
}
|
||||
|
||||
} else {
|
||||
val authorState by note.author!!.live.observeAsState()
|
||||
val author = authorState?.user
|
||||
|
||||
val replyAuthorBase = note.mentions?.first()
|
||||
|
||||
var userToComposeOn = author
|
||||
var userToComposeOn = note.author!!
|
||||
|
||||
if ( replyAuthorBase != null ) {
|
||||
val replyAuthorState by replyAuthorBase.live.observeAsState()
|
||||
val replyAuthor = replyAuthorState?.user
|
||||
|
||||
if (author == accountUser) {
|
||||
userToComposeOn = replyAuthor
|
||||
if (replyAuthorBase != null) {
|
||||
if (note.author == account.userProfile()) {
|
||||
userToComposeOn = replyAuthorBase
|
||||
}
|
||||
}
|
||||
|
||||
val noteEvent = note.event
|
||||
|
||||
userToComposeOn?.let { user ->
|
||||
userToComposeOn.let { user ->
|
||||
val hasNewMessages =
|
||||
if (noteEvent != null)
|
||||
noteEvent.createdAt > notificationCache.cache.load("Room/${userToComposeOn.pubkeyHex}", context)
|
||||
@ -134,8 +125,8 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
|
||||
false
|
||||
|
||||
ChannelName(
|
||||
channelPicture = { UserPicture(user, accountUser, size = 55.dp) },
|
||||
channelTitle = { UsernameDisplay(user, it) },
|
||||
channelPicture = { UserPicture(userToComposeOn, account.userProfile(), size = 55.dp) },
|
||||
channelTitle = { UsernameDisplay(userToComposeOn, it) },
|
||||
channelLastTime = noteEvent?.createdAt,
|
||||
channelLastContent = accountViewModel.decrypt(note),
|
||||
hasNewMessages = hasNewMessages,
|
||||
|
@ -59,8 +59,7 @@ fun ChatroomMessageCompose(baseNote: Note, routeForLastRead: String?, innerQuote
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val accountUserState by account.userProfile().live.observeAsState()
|
||||
val accountUser = accountUserState?.user
|
||||
val accountUser = account.userProfile()
|
||||
|
||||
var popupExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
@ -69,14 +68,11 @@ fun ChatroomMessageCompose(baseNote: Note, routeForLastRead: String?, innerQuote
|
||||
if (note?.event == null) {
|
||||
BlankNote(Modifier)
|
||||
} else {
|
||||
val authorState by note.author!!.live.observeAsState()
|
||||
val author = authorState?.user
|
||||
|
||||
var backgroundBubbleColor: Color
|
||||
var alignment: Arrangement.Horizontal
|
||||
var shape: Shape
|
||||
|
||||
if (author == accountUser) {
|
||||
if (note.author == accountUser) {
|
||||
backgroundBubbleColor = MaterialTheme.colors.primary.copy(alpha = 0.32f)
|
||||
alignment = Arrangement.End
|
||||
shape = ChatBubbleShapeMe
|
||||
@ -125,6 +121,9 @@ fun ChatroomMessageCompose(baseNote: Note, routeForLastRead: String?, innerQuote
|
||||
modifier = Modifier.padding(start = 10.dp, end = 10.dp, bottom = 5.dp),
|
||||
) {
|
||||
|
||||
val authorState by note.author!!.liveMetadata.observeAsState()
|
||||
val author = authorState?.user
|
||||
|
||||
if (innerQuote || author != accountUser && note.event is ChannelMessageEvent) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
@ -339,10 +339,7 @@ fun UserPicture(
|
||||
pictureModifier: Modifier = Modifier,
|
||||
onClick: ((User) -> Unit)? = null
|
||||
) {
|
||||
val accountState by baseUserAccount.live.observeAsState()
|
||||
val accountUser = accountState?.user ?: return
|
||||
|
||||
val userState by baseUser.live.observeAsState()
|
||||
val userState by baseUser.liveMetadata.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
Box(
|
||||
@ -367,6 +364,9 @@ fun UserPicture(
|
||||
|
||||
)
|
||||
|
||||
val accountState by baseUserAccount.liveFollows.observeAsState()
|
||||
val accountUser = accountState?.user ?: return
|
||||
|
||||
if (accountUser.isFollowing(user) || user == accountUser) {
|
||||
Box(
|
||||
Modifier
|
||||
|
@ -44,7 +44,7 @@ fun ReplyInformation(replyTo: MutableList<Note>?, mentions: List<User>?, prefix:
|
||||
val mentionSet = mentions.toSet()
|
||||
|
||||
mentionSet.toSet().forEachIndexed { idx, user ->
|
||||
val innerUserState by user.live.observeAsState()
|
||||
val innerUserState by user.liveMetadata.observeAsState()
|
||||
val innerUser = innerUserState?.user
|
||||
|
||||
innerUser?.let { myUser ->
|
||||
@ -123,7 +123,7 @@ fun ReplyInformationChannel(replyTo: MutableList<Note>?,
|
||||
val mentionSet = mentions.toSet()
|
||||
|
||||
mentionSet.forEachIndexed { idx, user ->
|
||||
val innerUserState by user.live.observeAsState()
|
||||
val innerUserState by user.liveMetadata.observeAsState()
|
||||
val innerUser = innerUserState?.user
|
||||
|
||||
innerUser?.let { myUser ->
|
||||
|
@ -34,14 +34,11 @@ fun UserCompose(baseUser: User, accountViewModel: AccountViewModel, navControlle
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val userState by baseUser.live.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
val ctx = LocalContext.current.applicationContext
|
||||
|
||||
Column(modifier =
|
||||
Modifier.clickable(
|
||||
onClick = { navController.navigate("User/${user.pubkeyHex}") }
|
||||
onClick = { navController.navigate("User/${baseUser.pubkeyHex}") }
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
@ -59,6 +56,9 @@ fun UserCompose(baseUser: User, accountViewModel: AccountViewModel, navControlle
|
||||
UsernameDisplay(baseUser)
|
||||
}
|
||||
|
||||
val userState by baseUser.liveMetadata.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
Text(
|
||||
user.info.about ?: "",
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
||||
@ -68,15 +68,15 @@ fun UserCompose(baseUser: User, accountViewModel: AccountViewModel, navControlle
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||
if (account?.isHidden(user) == false) {
|
||||
if (account.isHidden(baseUser)) {
|
||||
ShowUserButton {
|
||||
account.showUser(user.pubkeyHex)
|
||||
account.showUser(baseUser.pubkeyHex)
|
||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
||||
}
|
||||
} else if (account?.userProfile()?.isFollowing(user) == true) {
|
||||
UnfollowButton { account.unfollow(user) }
|
||||
} else if (account.userProfile().isFollowing(baseUser)) {
|
||||
UnfollowButton { account.unfollow(baseUser) }
|
||||
} else {
|
||||
FollowButton { account?.follow(user) }
|
||||
FollowButton { account.follow(baseUser) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ fun NoteUsernameDisplay(baseNote: Note, weight: Modifier = Modifier) {
|
||||
|
||||
@Composable
|
||||
fun UsernameDisplay(baseUser: User, weight: Modifier = Modifier) {
|
||||
val userState by baseUser.live.observeAsState()
|
||||
val userState by baseUser.liveMetadata.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
if (user.bestUsername() != null || user.bestDisplayName() != null) {
|
||||
|
@ -172,9 +172,6 @@ fun NoteMaster(baseNote: Note, accountViewModel: AccountViewModel, navController
|
||||
} else if (!account.isAcceptable(noteForReports)) {
|
||||
HiddenNote()
|
||||
} else {
|
||||
val authorState by note.author!!.live.observeAsState()
|
||||
val author = authorState?.user
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
@ -182,7 +179,7 @@ fun NoteMaster(baseNote: Note, accountViewModel: AccountViewModel, navController
|
||||
Row(modifier = Modifier
|
||||
.padding(start = 12.dp, end = 12.dp)
|
||||
.clickable(onClick = {
|
||||
author?.let {
|
||||
note.author?.let {
|
||||
navController.navigate("User/${it.pubkeyHex}")
|
||||
}
|
||||
})
|
||||
|
@ -41,6 +41,7 @@ import coil.compose.rememberAsyncImagePainter
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.NostrChatRoomDataSource
|
||||
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@ -70,13 +71,18 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxHeight().padding(vertical = 0.dp).weight(1f, true)
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(vertical = 0.dp)
|
||||
.weight(1f, true)
|
||||
) {
|
||||
ChatroomFeedView(feedViewModel, accountViewModel, navController, "Room/${userId}")
|
||||
}
|
||||
|
||||
//LAST ROW
|
||||
Row(modifier = Modifier.padding(10.dp).fillMaxWidth(),
|
||||
Row(modifier = Modifier
|
||||
.padding(10.dp)
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
@ -118,22 +124,23 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
||||
|
||||
@Composable
|
||||
fun ChatroomHeader(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
val authorState by baseUser.live.observeAsState()
|
||||
val author = authorState?.user
|
||||
|
||||
Column(modifier = Modifier.clickable(
|
||||
onClick = { navController.navigate("User/${author?.pubkeyHex}") }
|
||||
onClick = { navController.navigate("User/${baseUser.pubkeyHex}") }
|
||||
)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
|
||||
val authorState by baseUser.liveMetadata.observeAsState()
|
||||
val author = authorState?.user
|
||||
|
||||
AsyncImage(
|
||||
model = author?.profilePicture(),
|
||||
placeholder = rememberAsyncImagePainter("https://robohash.org/${author?.pubkeyHex}.png"),
|
||||
contentDescription = "Profile Image",
|
||||
modifier = Modifier
|
||||
.width(35.dp).height(35.dp)
|
||||
.width(35.dp)
|
||||
.height(35.dp)
|
||||
.clip(shape = CircleShape)
|
||||
)
|
||||
|
||||
|
@ -94,86 +94,92 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val accountUserState by account.userProfile().live.observeAsState()
|
||||
val accountUser = accountUserState?.user
|
||||
if (userId == null) return
|
||||
|
||||
if (userId != null && accountUser != null) {
|
||||
DisposableEffect(account) {
|
||||
NostrUserProfileDataSource.loadUserProfile(userId)
|
||||
NostrUserProfileFollowersDataSource.loadUserProfile(userId)
|
||||
NostrUserProfileFollowsDataSource.loadUserProfile(userId)
|
||||
DisposableEffect(account) {
|
||||
NostrUserProfileDataSource.loadUserProfile(userId)
|
||||
NostrUserProfileFollowersDataSource.loadUserProfile(userId)
|
||||
NostrUserProfileFollowsDataSource.loadUserProfile(userId)
|
||||
|
||||
onDispose {
|
||||
NostrUserProfileDataSource.stop()
|
||||
NostrUserProfileFollowsDataSource.stop()
|
||||
NostrUserProfileFollowersDataSource.stop()
|
||||
}
|
||||
onDispose {
|
||||
NostrUserProfileDataSource.stop()
|
||||
NostrUserProfileFollowsDataSource.stop()
|
||||
NostrUserProfileFollowersDataSource.stop()
|
||||
}
|
||||
}
|
||||
|
||||
val baseUser = NostrUserProfileDataSource.user ?: return
|
||||
val baseUser = NostrUserProfileDataSource.user ?: return
|
||||
|
||||
val userState by baseUser.live.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = MaterialTheme.colors.background
|
||||
) {
|
||||
Column() {
|
||||
ProfileHeader(baseUser, navController, account, accountViewModel)
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = MaterialTheme.colors.background
|
||||
) {
|
||||
Column() {
|
||||
ProfileHeader(user, navController, account, accountUser, accountViewModel)
|
||||
val pagerState = rememberPagerState()
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val pagerState = rememberPagerState()
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
Column(modifier = Modifier.padding()) {
|
||||
TabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
indicator = { tabPositions ->
|
||||
TabRowDefaults.Indicator(
|
||||
Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
},
|
||||
) {
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 0,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } },
|
||||
text = {
|
||||
Text(text = "Notes")
|
||||
}
|
||||
Column(modifier = Modifier.padding()) {
|
||||
TabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
indicator = { tabPositions ->
|
||||
TabRowDefaults.Indicator(
|
||||
Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 1,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } },
|
||||
text = {
|
||||
Text(text = "${user.follows?.size ?: "--"} Follows")
|
||||
}
|
||||
)
|
||||
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 2,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(2) } },
|
||||
text = {
|
||||
Text(text = "${user.followers?.size ?: "--"} Followers")
|
||||
}
|
||||
)
|
||||
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 3,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(3) } },
|
||||
text = {
|
||||
Text(text = "${user.relaysBeingUsed.size ?: "--"} / ${user.relays?.size ?: "--"} Relays")
|
||||
}
|
||||
)
|
||||
}
|
||||
HorizontalPager(count = 4, state = pagerState) {
|
||||
when (pagerState.currentPage) {
|
||||
0 -> TabNotes(user, accountViewModel, navController)
|
||||
1 -> TabFollows(user, accountViewModel, navController)
|
||||
2 -> TabFollowers(user, accountViewModel, navController)
|
||||
3 -> TabRelays(baseUser, accountViewModel, navController)
|
||||
},
|
||||
) {
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 0,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } },
|
||||
text = {
|
||||
Text(text = "Notes")
|
||||
}
|
||||
)
|
||||
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 1,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } },
|
||||
text = {
|
||||
val userState by baseUser.liveFollows.observeAsState()
|
||||
val userFollows = userState?.user?.follows?.size ?: "--"
|
||||
|
||||
Text(text = "$userFollows Follows")
|
||||
}
|
||||
)
|
||||
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 2,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(2) } },
|
||||
text = {
|
||||
val userState by baseUser.liveFollows.observeAsState()
|
||||
val userFollows = userState?.user?.followers?.size ?: "--"
|
||||
|
||||
Text(text = "$userFollows Followers")
|
||||
}
|
||||
)
|
||||
|
||||
Tab(
|
||||
selected = pagerState.currentPage == 3,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(3) } },
|
||||
text = {
|
||||
val userState by baseUser.liveRelays.observeAsState()
|
||||
val userRelaysBeingUsed = userState?.user?.relaysBeingUsed?.size ?: "--"
|
||||
|
||||
val userStateRelayInfo by baseUser.liveRelayInfo.observeAsState()
|
||||
val userRelays = userStateRelayInfo?.user?.relays?.size ?: "--"
|
||||
|
||||
Text(text = "$userRelaysBeingUsed / $userRelays Relays")
|
||||
}
|
||||
)
|
||||
}
|
||||
HorizontalPager(count = 4, state = pagerState) {
|
||||
when (pagerState.currentPage) {
|
||||
0 -> TabNotes(baseUser, accountViewModel, navController)
|
||||
1 -> TabFollows(baseUser, accountViewModel, navController)
|
||||
2 -> TabFollowers(baseUser, accountViewModel, navController)
|
||||
3 -> TabRelays(baseUser, accountViewModel, navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,36 +189,19 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
||||
|
||||
@Composable
|
||||
private fun ProfileHeader(
|
||||
user: User,
|
||||
baseUser: User,
|
||||
navController: NavController,
|
||||
account: Account,
|
||||
accountUser: User,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val ctx = LocalContext.current.applicationContext
|
||||
var popupExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
val accountUserState by account.userProfile().liveFollows.observeAsState()
|
||||
val accountUser = accountUserState?.user ?: return
|
||||
|
||||
Box {
|
||||
val banner = user.info.banner
|
||||
if (banner != null && banner.isNotBlank()) {
|
||||
AsyncImage(
|
||||
model = banner,
|
||||
contentDescription = "Profile Image",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(125.dp)
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.profile_banner),
|
||||
contentDescription = "Profile Banner",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(125.dp)
|
||||
)
|
||||
}
|
||||
DrawBanner(baseUser)
|
||||
|
||||
Box(modifier = Modifier
|
||||
.padding(horizontal = 10.dp)
|
||||
@ -237,7 +226,7 @@ private fun ProfileHeader(
|
||||
contentDescription = "More Options",
|
||||
)
|
||||
|
||||
UserProfileDropDownMenu(user, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||
UserProfileDropDownMenu(baseUser, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||
}
|
||||
|
||||
}
|
||||
@ -255,7 +244,7 @@ private fun ProfileHeader(
|
||||
) {
|
||||
|
||||
UserPicture(
|
||||
user, navController, account.userProfile(), 100.dp,
|
||||
baseUser, navController, account.userProfile(), 100.dp,
|
||||
pictureModifier = Modifier.border(
|
||||
3.dp,
|
||||
MaterialTheme.colors.background,
|
||||
@ -268,52 +257,88 @@ private fun ProfileHeader(
|
||||
Row(modifier = Modifier
|
||||
.height(35.dp)
|
||||
.padding(bottom = 3.dp)) {
|
||||
MessageButton(user, navController)
|
||||
MessageButton(baseUser, navController)
|
||||
|
||||
if (accountUser == user && account.isWriteable()) {
|
||||
if (accountUser == baseUser && account.isWriteable()) {
|
||||
NSecCopyButton(account)
|
||||
}
|
||||
|
||||
NPubCopyButton(user)
|
||||
NPubCopyButton(baseUser)
|
||||
|
||||
if (accountUser == user) {
|
||||
if (accountUser == baseUser) {
|
||||
EditButton(account)
|
||||
} else {
|
||||
if (!account.isHidden(user)) {
|
||||
if (account.isHidden(baseUser)) {
|
||||
ShowUserButton {
|
||||
account.showUser(user.pubkeyHex)
|
||||
account.showUser(baseUser.pubkeyHex)
|
||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
||||
}
|
||||
} else if (accountUser.isFollowing(user)) {
|
||||
UnfollowButton { account.unfollow(user) }
|
||||
} else if (accountUser.isFollowing(baseUser)) {
|
||||
UnfollowButton { account.unfollow(baseUser) }
|
||||
} else {
|
||||
FollowButton { account.follow(user) }
|
||||
FollowButton { account.follow(baseUser) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
user.bestDisplayName() ?: "",
|
||||
modifier = Modifier.padding(top = 7.dp),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 25.sp
|
||||
)
|
||||
Text(
|
||||
" @${user.bestUsername()}",
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
|
||||
)
|
||||
Text(
|
||||
"${user.info.about}",
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)
|
||||
)
|
||||
DrawAdditionalInfo(baseUser)
|
||||
|
||||
Divider(modifier = Modifier.padding(top = 6.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DrawAdditionalInfo(baseUser: User) {
|
||||
val userState by baseUser.liveMetadata.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
Text(
|
||||
user.bestDisplayName() ?: "",
|
||||
modifier = Modifier.padding(top = 7.dp),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 25.sp
|
||||
)
|
||||
Text(
|
||||
" @${user.bestUsername()}",
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
|
||||
)
|
||||
Text(
|
||||
"${user.info.about}",
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DrawBanner(baseUser: User) {
|
||||
val userState by baseUser.liveMetadata.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
val banner = user.info.banner
|
||||
|
||||
if (banner != null && banner.isNotBlank()) {
|
||||
AsyncImage(
|
||||
model = banner,
|
||||
contentDescription = "Profile Image",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(125.dp)
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.profile_banner),
|
||||
contentDescription = "Profile Banner",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(125.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabNotes(user: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
@ -560,7 +585,7 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () ->
|
||||
|
||||
if ( account.userProfile() != user) {
|
||||
Divider()
|
||||
if (!account.isHidden(user)) {
|
||||
if (account.isHidden(user)) {
|
||||
DropdownMenuItem(onClick = {
|
||||
user.let {
|
||||
accountViewModel.show(
|
||||
|
@ -210,9 +210,6 @@ fun UserLine(
|
||||
account: Account,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val userState by baseUser.live.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
@ -226,7 +223,7 @@ fun UserLine(
|
||||
)
|
||||
) {
|
||||
|
||||
UserPicture(user, account.userProfile(), 55.dp, Modifier, null)
|
||||
UserPicture(baseUser, account.userProfile(), 55.dp, Modifier, null)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@ -237,6 +234,9 @@ fun UserLine(
|
||||
UsernameDisplay(baseUser)
|
||||
}
|
||||
|
||||
val userState by baseUser.liveMetadata.observeAsState()
|
||||
val user = userState?.user ?: return
|
||||
|
||||
Text(
|
||||
user.info.about?.take(100) ?: "",
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
||||
|
Loading…
x
Reference in New Issue
Block a user