mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-19 01:50:42 +02:00
Moving Picture and Display Name Observables to leaf UI nodes.
This commit is contained in:
@@ -76,19 +76,12 @@ fun BoostSetCompose(likeSetCard: BoostSetCard, isInnerNote: Boolean = false, rou
|
|||||||
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) {
|
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) {
|
||||||
FlowRow() {
|
FlowRow() {
|
||||||
likeSetCard.boostEvents.forEach {
|
likeSetCard.boostEvents.forEach {
|
||||||
val cardNoteState by it.live.observeAsState()
|
NoteAuthorPicture(
|
||||||
val cardNote = cardNoteState?.note
|
note = it,
|
||||||
|
navController = navController,
|
||||||
if (cardNote?.author != null) {
|
userAccount = account.userProfile(),
|
||||||
val userState by cardNote.author!!.live.observeAsState()
|
size = 35.dp
|
||||||
|
)
|
||||||
UserPicture(
|
|
||||||
user = userState?.user,
|
|
||||||
navController = navController,
|
|
||||||
userAccount = account.userProfile(),
|
|
||||||
size = 35.dp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -134,7 +134,7 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
|
|||||||
false
|
false
|
||||||
|
|
||||||
ChannelName(
|
ChannelName(
|
||||||
channelPicture = { UserPicture(user = user, userAccount = accountUser, size = 55.dp) },
|
channelPicture = { UserPicture(user, accountUser, size = 55.dp) },
|
||||||
channelTitle = { UsernameDisplay(user, it) },
|
channelTitle = { UsernameDisplay(user, it) },
|
||||||
channelLastTime = noteEvent?.createdAt,
|
channelLastTime = noteEvent?.createdAt,
|
||||||
channelLastContent = accountViewModel.decrypt(note),
|
channelLastContent = accountViewModel.decrypt(note),
|
||||||
|
@@ -76,19 +76,12 @@ fun LikeSetCompose(likeSetCard: LikeSetCard, modifier: Modifier = Modifier, isIn
|
|||||||
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) {
|
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) {
|
||||||
FlowRow() {
|
FlowRow() {
|
||||||
likeSetCard.likeEvents.forEach {
|
likeSetCard.likeEvents.forEach {
|
||||||
val cardNoteState by it.live.observeAsState()
|
NoteAuthorPicture(
|
||||||
val cardNote = cardNoteState?.note
|
note = it,
|
||||||
|
navController = navController,
|
||||||
if (cardNote?.author != null) {
|
userAccount = account.userProfile(),
|
||||||
val userState by cardNote.author!!.live.observeAsState()
|
size = 35.dp
|
||||||
|
)
|
||||||
UserPicture(
|
|
||||||
user = userState?.user,
|
|
||||||
navController = navController,
|
|
||||||
userAccount = account.userProfile(),
|
|
||||||
size = 35.dp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -95,9 +95,6 @@ fun NoteCompose(
|
|||||||
onLongClick = { popupExpanded = true },
|
onLongClick = { popupExpanded = true },
|
||||||
), isInnerNote)
|
), isInnerNote)
|
||||||
} else {
|
} else {
|
||||||
val authorState by note.author?.live!!.observeAsState()
|
|
||||||
val author = authorState?.user ?: return // if it has event, it should have an author
|
|
||||||
|
|
||||||
val isNew = routeForLastRead?.run {
|
val isNew = routeForLastRead?.run {
|
||||||
val lastTime = NotificationCache.load(this, context)
|
val lastTime = NotificationCache.load(this, context)
|
||||||
|
|
||||||
@@ -145,20 +142,20 @@ fun NoteCompose(
|
|||||||
Box(modifier = Modifier
|
Box(modifier = Modifier
|
||||||
.width(55.dp)
|
.width(55.dp)
|
||||||
.padding(0.dp)) {
|
.padding(0.dp)) {
|
||||||
UserPicture(author, navController, account.userProfile(), 55.dp)
|
|
||||||
|
|
||||||
// boosted picture
|
NoteAuthorPicture(note, navController, account.userProfile(), 55.dp)
|
||||||
val boostedPosts = note.replyTo
|
|
||||||
if (note.event is RepostEvent && boostedPosts != null && boostedPosts.isNotEmpty()) {
|
if (note.event is RepostEvent) {
|
||||||
val boostedAuthor = boostedPosts[0].author
|
note.replyTo?.lastOrNull()?.let {
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.width(30.dp)
|
.width(30.dp)
|
||||||
.height(30.dp)
|
.height(30.dp)
|
||||||
.align(Alignment.BottomEnd)) {
|
.align(Alignment.BottomEnd)) {
|
||||||
UserPicture(boostedAuthor, navController, account.userProfile(), 35.dp,
|
NoteAuthorPicture(it, navController, account.userProfile(), 35.dp,
|
||||||
pictureModifier = Modifier.border(2.dp, MaterialTheme.colors.background, CircleShape)
|
pictureModifier = Modifier.border(2.dp, MaterialTheme.colors.background, CircleShape)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +194,7 @@ fun NoteCompose(
|
|||||||
|
|
||||||
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) {
|
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
if (author != null)
|
NoteUsernameDisplay(note, Modifier.weight(1f))
|
||||||
UsernameDisplay(author, Modifier.weight(1f))
|
|
||||||
|
|
||||||
if (note.event !is RepostEvent) {
|
if (note.event !is RepostEvent) {
|
||||||
Text(
|
Text(
|
||||||
@@ -274,40 +270,42 @@ fun NoteCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UserPicture(
|
fun NoteAuthorPicture(
|
||||||
user: User?,
|
note: Note,
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
userAccount: User,
|
userAccount: User,
|
||||||
size: Dp,
|
size: Dp,
|
||||||
pictureModifier: Modifier = Modifier
|
pictureModifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
UserPicture(user, userAccount, size, pictureModifier) {
|
NoteAuthorPicture(note, userAccount, size, pictureModifier) {
|
||||||
user?.let {
|
navController.navigate("User/${it.pubkeyHex}")
|
||||||
navController.navigate("User/${it.pubkeyHex}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UserPicture(
|
fun NoteAuthorPicture(
|
||||||
user: User?,
|
baseNote: Note,
|
||||||
userAccount: User,
|
baseUserAccount: User,
|
||||||
size: Dp,
|
size: Dp,
|
||||||
pictureModifier: Modifier = Modifier,
|
pictureModifier: Modifier = Modifier,
|
||||||
onClick: (() -> Unit)? = null
|
onClick: ((User) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val accountState by userAccount.live.observeAsState()
|
val noteState by baseNote.live.observeAsState()
|
||||||
val accountUser = accountState?.user ?: return
|
val note = noteState?.note ?: return
|
||||||
|
|
||||||
|
val author = note.author
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.width(size)
|
.width(size)
|
||||||
.height(size)) {
|
.height(size)) {
|
||||||
if (user == null) {
|
if (author == null) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = "https://robohash.org/ohno.png",
|
model = "https://robohash.org/ohno.png",
|
||||||
contentDescription = "Profile Image",
|
contentDescription = "Unknown Author",
|
||||||
placeholder = rememberAsyncImagePainter("https://robohash.org/ohno.png"),
|
placeholder = rememberAsyncImagePainter("https://robohash.org/ohno.png"),
|
||||||
modifier = pictureModifier
|
modifier = pictureModifier
|
||||||
.fillMaxSize(1f)
|
.fillMaxSize(1f)
|
||||||
@@ -315,54 +313,88 @@ fun UserPicture(
|
|||||||
.background(MaterialTheme.colors.background)
|
.background(MaterialTheme.colors.background)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val userState by user.live.observeAsState()
|
UserPicture(author, baseUserAccount, size, pictureModifier, onClick)
|
||||||
val userLive = userState?.user ?: return
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AsyncImage(
|
@Composable
|
||||||
model = userLive.profilePicture(),
|
fun UserPicture(
|
||||||
contentDescription = "Profile Image",
|
user: User,
|
||||||
placeholder = rememberAsyncImagePainter("https://robohash.org/${userLive.pubkeyHex}.png"),
|
navController: NavController,
|
||||||
modifier = pictureModifier
|
userAccount: User,
|
||||||
.fillMaxSize(1f)
|
size: Dp,
|
||||||
.clip(shape = CircleShape)
|
pictureModifier: Modifier = Modifier
|
||||||
.background(MaterialTheme.colors.background)
|
) {
|
||||||
.run {
|
UserPicture(user, userAccount, size, pictureModifier) {
|
||||||
if (onClick != null)
|
navController.navigate("User/${it.pubkeyHex}")
|
||||||
this.clickable(onClick = onClick)
|
}
|
||||||
else
|
}
|
||||||
this
|
|
||||||
}
|
|
||||||
|
|
||||||
)
|
@Composable
|
||||||
|
fun UserPicture(
|
||||||
|
baseUser: User,
|
||||||
|
baseUserAccount: User,
|
||||||
|
size: Dp,
|
||||||
|
pictureModifier: Modifier = Modifier,
|
||||||
|
onClick: ((User) -> Unit)? = null
|
||||||
|
) {
|
||||||
|
val accountState by baseUserAccount.live.observeAsState()
|
||||||
|
val accountUser = accountState?.user ?: return
|
||||||
|
|
||||||
if (accountUser.isFollowing(userLive) || userLive == accountUser) {
|
val userState by baseUser.live.observeAsState()
|
||||||
Box(
|
val user = userState?.user ?: return
|
||||||
Modifier
|
|
||||||
.width(size.div(3.5f))
|
|
||||||
.height(size.div(3.5f))
|
|
||||||
.align(Alignment.TopEnd),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
// Background for the transparent checkmark
|
|
||||||
Text(
|
|
||||||
"x",
|
|
||||||
Modifier
|
|
||||||
.padding(4.dp)
|
|
||||||
.fillMaxSize()
|
|
||||||
.align(Alignment.Center)
|
|
||||||
.background(MaterialTheme.colors.background)
|
|
||||||
.clip(shape = CircleShape)
|
|
||||||
)
|
|
||||||
|
|
||||||
Icon(
|
Box(
|
||||||
painter = painterResource(R.drawable.ic_verified),
|
Modifier
|
||||||
"Following",
|
.width(size)
|
||||||
modifier = Modifier.fillMaxSize(),
|
.height(size)) {
|
||||||
tint = Following
|
|
||||||
)
|
AsyncImage(
|
||||||
|
model = user.profilePicture(),
|
||||||
|
contentDescription = "Profile Image",
|
||||||
|
placeholder = rememberAsyncImagePainter("https://robohash.org/${user.pubkeyHex}.png"),
|
||||||
|
modifier = pictureModifier
|
||||||
|
.fillMaxSize(1f)
|
||||||
|
.clip(shape = CircleShape)
|
||||||
|
.background(MaterialTheme.colors.background)
|
||||||
|
.run {
|
||||||
|
if (onClick != null)
|
||||||
|
this.clickable(onClick = { onClick(user) } )
|
||||||
|
else
|
||||||
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
if (accountUser.isFollowing(user) || user == accountUser) {
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.width(size.div(3.5f))
|
||||||
|
.height(size.div(3.5f))
|
||||||
|
.align(Alignment.TopEnd),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
// Background for the transparent checkmark
|
||||||
|
Text(
|
||||||
|
"x",
|
||||||
|
Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
.fillMaxSize()
|
||||||
|
.align(Alignment.Center)
|
||||||
|
.background(MaterialTheme.colors.background)
|
||||||
|
.clip(shape = CircleShape)
|
||||||
|
)
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_verified),
|
||||||
|
"Following",
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
tint = Following
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,11 +52,11 @@ fun UserCompose(baseUser: User, accountViewModel: AccountViewModel, navControlle
|
|||||||
top = 10.dp)
|
top = 10.dp)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
UserPicture(user, navController, account.userProfile(), 55.dp)
|
UserPicture(baseUser, navController, account.userProfile(), 55.dp)
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(start = 10.dp).weight(1f)) {
|
Column(modifier = Modifier.padding(start = 10.dp).weight(1f)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
UsernameDisplay(user)
|
UsernameDisplay(baseUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
@@ -3,42 +3,61 @@ package com.vitorpamplona.amethyst.ui.note
|
|||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UsernameDisplay(user: User, weight: Modifier = Modifier) {
|
fun NoteUsernameDisplay(baseNote: Note, weight: Modifier = Modifier) {
|
||||||
if (user.bestUsername() != null || user.bestDisplayName() != null) {
|
val noteState by baseNote.live.observeAsState()
|
||||||
if (user.bestDisplayName().isNullOrBlank()) {
|
val note = noteState?.note ?: return
|
||||||
Text(
|
|
||||||
"@${(user.bestUsername() ?: "")}",
|
val author = note.author
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
maxLines = 1,
|
if (author != null) {
|
||||||
overflow = TextOverflow.Ellipsis,
|
UsernameDisplay(author, weight)
|
||||||
modifier = weight
|
}
|
||||||
)
|
}
|
||||||
} else {
|
|
||||||
Text(
|
@Composable
|
||||||
user.bestDisplayName() ?: "",
|
fun UsernameDisplay(baseUser: User, weight: Modifier = Modifier) {
|
||||||
fontWeight = FontWeight.Bold,
|
val userState by baseUser.live.observeAsState()
|
||||||
)
|
val user = userState?.user ?: return
|
||||||
Text(
|
|
||||||
"@${(user.bestUsername() ?: "")}",
|
if (user.bestUsername() != null || user.bestDisplayName() != null) {
|
||||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
if (user.bestDisplayName().isNullOrBlank()) {
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = weight
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Text(
|
Text(
|
||||||
user.pubkeyDisplayHex,
|
"@${(user.bestUsername() ?: "")}",
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = weight
|
modifier = weight
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
Text(
|
||||||
|
user.bestDisplayName() ?: "",
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"@${(user.bestUsername() ?: "")}",
|
||||||
|
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = weight
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Text(
|
||||||
|
user.pubkeyDisplayHex,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = weight
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
@@ -41,7 +41,9 @@ import com.vitorpamplona.amethyst.model.Note
|
|||||||
import com.vitorpamplona.amethyst.ui.components.RichTextViewer
|
import com.vitorpamplona.amethyst.ui.components.RichTextViewer
|
||||||
import com.vitorpamplona.amethyst.ui.note.BlankNote
|
import com.vitorpamplona.amethyst.ui.note.BlankNote
|
||||||
import com.vitorpamplona.amethyst.ui.note.HiddenNote
|
import com.vitorpamplona.amethyst.ui.note.HiddenNote
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay
|
||||||
import com.vitorpamplona.amethyst.ui.note.ReactionsRow
|
import com.vitorpamplona.amethyst.ui.note.ReactionsRow
|
||||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||||
@@ -185,12 +187,16 @@ fun NoteMaster(baseNote: Note, accountViewModel: AccountViewModel, navController
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
UserPicture(user = author, navController, userAccount = account.userProfile(), size = 55.dp)
|
NoteAuthorPicture(
|
||||||
|
note = baseNote,
|
||||||
|
navController = navController,
|
||||||
|
userAccount = account.userProfile(),
|
||||||
|
size = 55.dp
|
||||||
|
)
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
if (author != null)
|
NoteUsernameDisplay(baseNote)
|
||||||
UsernameDisplay(author)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
@@ -139,8 +139,7 @@ fun ChatroomHeader(baseUser: User, accountViewModel: AccountViewModel, navContro
|
|||||||
|
|
||||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
if (author != null)
|
UsernameDisplay(baseUser)
|
||||||
UsernameDisplay(author)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -234,7 +234,7 @@ fun UserLine(
|
|||||||
.weight(1f)
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
UsernameDisplay(user)
|
UsernameDisplay(baseUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
Reference in New Issue
Block a user