mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-26 12:24:03 +02:00
Performance Improvements
This commit is contained in:
parent
743a4c9d87
commit
f9d652f849
@ -1134,7 +1134,7 @@ class Account(
|
|||||||
user.countReportAuthorsBy(followingKeySet()) < 5
|
user.countReportAuthorsBy(followingKeySet()) < 5
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAcceptableDirect(note: Note): Boolean {
|
private fun isAcceptableDirect(note: Note): Boolean {
|
||||||
if (!warnAboutPostsWithReports) {
|
if (!warnAboutPostsWithReports) {
|
||||||
return note.reportsBy(userProfile()).isEmpty()
|
return note.reportsBy(userProfile()).isEmpty()
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class PublicChatChannel(idHex: String) : Channel(idHex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun profilePicture(): String? {
|
override fun profilePicture(): String? {
|
||||||
if (info.picture.isNullOrBlank()) return null
|
if (info.picture.isNullOrBlank()) return super.profilePicture()
|
||||||
return info.picture ?: super.profilePicture()
|
return info.picture ?: super.profilePicture()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class LiveActivitiesChannel(val address: ATag) : Channel(address.toTag()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun profilePicture(): String? {
|
override fun profilePicture(): String? {
|
||||||
return info?.image()?.ifBlank { null } ?: super.profilePicture()
|
return info?.image()?.ifBlank { null }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun anyNameStartsWith(prefix: String): Boolean {
|
override fun anyNameStartsWith(prefix: String): Boolean {
|
||||||
|
@ -12,6 +12,8 @@ import com.vitorpamplona.amethyst.service.model.MetadataEvent
|
|||||||
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
||||||
import com.vitorpamplona.amethyst.service.relays.EOSETime
|
import com.vitorpamplona.amethyst.service.relays.EOSETime
|
||||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
||||||
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
||||||
import fr.acinq.secp256k1.Hex
|
import fr.acinq.secp256k1.Hex
|
||||||
@ -237,6 +239,7 @@ class User(val pubkeyHex: String) {
|
|||||||
info = newUserInfo
|
info = newUserInfo
|
||||||
info?.latestMetadata = latestMetadata
|
info?.latestMetadata = latestMetadata
|
||||||
info?.updatedMetadataAt = latestMetadata.createdAt
|
info?.updatedMetadataAt = latestMetadata.createdAt
|
||||||
|
info?.tags = latestMetadata.tags.toImmutableListOfLists()
|
||||||
|
|
||||||
if (newUserInfo.lud16.isNullOrBlank() && newUserInfo.lud06?.lowercase()?.startsWith("lnurl") == true) {
|
if (newUserInfo.lud16.isNullOrBlank() && newUserInfo.lud06?.lowercase()?.startsWith("lnurl") == true) {
|
||||||
try {
|
try {
|
||||||
@ -421,6 +424,7 @@ class UserMetadata {
|
|||||||
|
|
||||||
var updatedMetadataAt: Long = 0
|
var updatedMetadataAt: Long = 0
|
||||||
var latestMetadata: MetadataEvent? = null
|
var latestMetadata: MetadataEvent? = null
|
||||||
|
var tags: ImmutableListOfLists<String>? = null
|
||||||
|
|
||||||
fun anyName(): String? {
|
fun anyName(): String? {
|
||||||
return display_name ?: displayName ?: name ?: username
|
return display_name ?: displayName ?: name ?: username
|
||||||
@ -434,6 +438,23 @@ class UserMetadata {
|
|||||||
fun lnAddress(): String? {
|
fun lnAddress(): String? {
|
||||||
return (lud16?.trim() ?: lud06?.trim())?.ifBlank { null }
|
return (lud16?.trim() ?: lud06?.trim())?.ifBlank { null }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun bestUsername(): String? {
|
||||||
|
return name?.ifBlank { null } ?: username?.ifBlank { null }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bestDisplayName(): String? {
|
||||||
|
return displayName?.ifBlank { null } ?: display_name?.ifBlank { null }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nip05(): String? {
|
||||||
|
return nip05?.ifBlank { null }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun profilePicture(): String? {
|
||||||
|
if (picture.isNullOrBlank()) picture = null
|
||||||
|
return picture
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserLiveData(val user: User) : LiveData<UserState>(UserState(user)) {
|
class UserLiveData(val user: User) : LiveData<UserState>(UserState(user)) {
|
||||||
|
@ -65,6 +65,7 @@ import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture
|
|||||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchBarViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchBarViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
@ -389,7 +390,7 @@ fun UserComposeForChat(
|
|||||||
),
|
),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
ClickableUserPicture(baseUser, 55.dp, accountViewModel)
|
ClickableUserPicture(baseUser, Size55dp, accountViewModel)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.components
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.LruCache
|
import android.util.LruCache
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.text.ClickableText
|
import androidx.compose.foundation.text.ClickableText
|
||||||
@ -26,6 +27,8 @@ import androidx.compose.ui.text.style.TextDirection
|
|||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.distinctUntilChanged
|
||||||
|
import androidx.lifecycle.map
|
||||||
import com.halilibo.richtext.markdown.Markdown
|
import com.halilibo.richtext.markdown.Markdown
|
||||||
import com.halilibo.richtext.markdown.MarkdownParseOptions
|
import com.halilibo.richtext.markdown.MarkdownParseOptions
|
||||||
import com.halilibo.richtext.ui.HeadingStyle
|
import com.halilibo.richtext.ui.HeadingStyle
|
||||||
@ -40,7 +43,6 @@ import com.vitorpamplona.amethyst.model.User
|
|||||||
import com.vitorpamplona.amethyst.model.checkForHashtagWithIcon
|
import com.vitorpamplona.amethyst.model.checkForHashtagWithIcon
|
||||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||||
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.theme.MarkdownTextStyle
|
import com.vitorpamplona.amethyst.ui.theme.MarkdownTextStyle
|
||||||
@ -751,7 +753,11 @@ fun BechLink(word: String, canPreview: Boolean, backgroundColor: MutableState<Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedLink = LoadedBechLink(returningNote, it)
|
val newLink = LoadedBechLink(returningNote, it)
|
||||||
|
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
loadedLink = newLink
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -838,10 +844,12 @@ fun HashTag(word: String, nav: (String) -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (myTag != null) {
|
if (myTag != null) {
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
tagSuffixPair = Pair(myTag, mySuffix)
|
tagSuffixPair = Pair(myTag, mySuffix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tagSuffixPair?.let { tagPair ->
|
tagSuffixPair?.let { tagPair ->
|
||||||
val hashtagIcon = remember(tagPair.first) { checkForHashtagWithIcon(tagPair.first) }
|
val hashtagIcon = remember(tagPair.first) { checkForHashtagWithIcon(tagPair.first) }
|
||||||
@ -922,10 +930,13 @@ fun TagLink(word: String, tags: ImmutableListOfLists<String>, canPreview: Boolea
|
|||||||
if (tag.size > 1) {
|
if (tag.size > 1) {
|
||||||
if (tag[0] == "p") {
|
if (tag[0] == "p") {
|
||||||
LocalCache.checkGetOrCreateUser(tag[1])?.let {
|
LocalCache.checkGetOrCreateUser(tag[1])?.let {
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
loadedTag = LoadedTag(it, null, suffix)
|
loadedTag = LoadedTag(it, null, suffix)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (tag[0] == "e" || tag[0] == "a") {
|
} else if (tag[0] == "e" || tag[0] == "a") {
|
||||||
LocalCache.checkGetOrCreateNote(tag[1])?.let {
|
LocalCache.checkGetOrCreateNote(tag[1])?.let {
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
loadedTag = LoadedTag(null, it, suffix)
|
loadedTag = LoadedTag(null, it, suffix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -934,6 +945,7 @@ fun TagLink(word: String, tags: ImmutableListOfLists<String>, canPreview: Boolea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (loadedTag == null) {
|
if (loadedTag == null) {
|
||||||
Text(
|
Text(
|
||||||
@ -995,25 +1007,23 @@ private fun DisplayUserFromTag(
|
|||||||
) {
|
) {
|
||||||
val route = remember { "User/${baseUser.pubkeyHex}" }
|
val route = remember { "User/${baseUser.pubkeyHex}" }
|
||||||
val suffix = remember { "$addedChars " }
|
val suffix = remember { "$addedChars " }
|
||||||
|
val hex = remember { baseUser.pubkeyDisplayHex() }
|
||||||
|
|
||||||
val innerUserState by baseUser.live().metadata.observeAsState()
|
val meta by baseUser.live().metadata.map {
|
||||||
val displayName by remember(innerUserState) {
|
it.user.info
|
||||||
derivedStateOf {
|
}.distinctUntilChanged().observeAsState(baseUser.info)
|
||||||
innerUserState?.user?.toBestDisplayName() ?: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val userTags by remember(innerUserState) {
|
|
||||||
derivedStateOf {
|
|
||||||
innerUserState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Crossfade(targetState = meta) {
|
||||||
|
val displayName = remember(it) {
|
||||||
|
it?.bestDisplayName() ?: hex
|
||||||
|
}
|
||||||
CreateClickableTextWithEmoji(
|
CreateClickableTextWithEmoji(
|
||||||
clickablePart = displayName,
|
clickablePart = displayName,
|
||||||
suffix = suffix,
|
suffix = suffix,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
route = route,
|
route = route,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
tags = userTags
|
tags = it?.tags ?: ImmutableListOfLists()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -50,7 +50,7 @@ fun RobohashAsyncImage(
|
|||||||
@Composable
|
@Composable
|
||||||
fun RobohashFallbackAsyncImage(
|
fun RobohashFallbackAsyncImage(
|
||||||
robot: String,
|
robot: String,
|
||||||
model: String,
|
model: String?,
|
||||||
contentDescription: String?,
|
contentDescription: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
alignment: Alignment = Alignment.Center,
|
alignment: Alignment = Alignment.Center,
|
||||||
@ -91,18 +91,6 @@ fun RobohashAsyncImageProxy(
|
|||||||
colorFilter: ColorFilter? = null,
|
colorFilter: ColorFilter? = null,
|
||||||
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality
|
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality
|
||||||
) {
|
) {
|
||||||
if (model == null) {
|
|
||||||
RobohashAsyncImage(
|
|
||||||
robot = robot,
|
|
||||||
contentDescription = contentDescription,
|
|
||||||
modifier = modifier,
|
|
||||||
alignment = alignment,
|
|
||||||
contentScale = contentScale,
|
|
||||||
alpha = alpha,
|
|
||||||
colorFilter = colorFilter,
|
|
||||||
filterQuality = filterQuality
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
RobohashFallbackAsyncImage(
|
RobohashFallbackAsyncImage(
|
||||||
robot = robot,
|
robot = robot,
|
||||||
model = model,
|
model = model,
|
||||||
@ -115,4 +103,3 @@ fun RobohashAsyncImageProxy(
|
|||||||
filterQuality = filterQuality
|
filterQuality = filterQuality
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.components
|
package com.vitorpamplona.amethyst.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@ -28,6 +29,7 @@ import androidx.compose.ui.res.painterResource
|
|||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.map
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
@ -109,31 +111,28 @@ fun ObserveDisplayNip05Status(baseNote: Note, columnModifier: Modifier = Modifie
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ObserveDisplayNip05Status(baseUser: User, columnModifier: Modifier = Modifier) {
|
fun ObserveDisplayNip05Status(baseUser: User, columnModifier: Modifier = Modifier) {
|
||||||
val userState by baseUser.live().metadata.observeAsState()
|
val nip05 by baseUser.live().metadata.map {
|
||||||
val isValidNIP05 by remember(userState) {
|
it.user.nip05()
|
||||||
derivedStateOf {
|
}.observeAsState()
|
||||||
userState?.user?.nip05()?.split("@")?.size == 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val nip05 by remember(userState) {
|
|
||||||
derivedStateOf {
|
|
||||||
userState?.user?.nip05()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isValidNIP05) {
|
Crossfade(targetState = nip05, modifier = columnModifier) {
|
||||||
nip05?.let {
|
if (it != null) {
|
||||||
|
val isValid = it.split("@").size == 2
|
||||||
|
if (isValid) {
|
||||||
DisplayNIP05Line(it, baseUser, columnModifier)
|
DisplayNIP05Line(it, baseUser, columnModifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DisplayNIP05Line(nip05: String, baseUser: User, columnModifier: Modifier = Modifier) {
|
private fun DisplayNIP05Line(nip05: String, baseUser: User, columnModifier: Modifier = Modifier) {
|
||||||
Column(modifier = columnModifier) {
|
Column(modifier = columnModifier) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
val nip05Verified = nip05VerificationAsAState(baseUser.info!!, baseUser.pubkeyHex)
|
val nip05Verified = nip05VerificationAsAState(baseUser.info!!, baseUser.pubkeyHex)
|
||||||
DisplayNIP05(nip05, nip05Verified)
|
Crossfade(targetState = nip05Verified) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
DisplayNIP05(nip05, it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,7 +149,7 @@ private fun DisplayNIP05(
|
|||||||
|
|
||||||
if (user != "_") {
|
if (user != "_") {
|
||||||
Text(
|
Text(
|
||||||
text = AnnotatedString(user),
|
text = remember(nip05) { AnnotatedString(user) },
|
||||||
color = MaterialTheme.colors.placeholderText,
|
color = MaterialTheme.colors.placeholderText,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
@ -160,7 +159,7 @@ private fun DisplayNIP05(
|
|||||||
NIP05VerifiedSymbol(nip05Verified)
|
NIP05VerifiedSymbol(nip05Verified)
|
||||||
|
|
||||||
ClickableText(
|
ClickableText(
|
||||||
text = AnnotatedString(domain),
|
text = remember(nip05) { AnnotatedString(domain) },
|
||||||
onClick = { runCatching { uri.openUri("https://$domain") } },
|
onClick = { runCatching { uri.openUri("https://$domain") } },
|
||||||
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary.copy(0.52f)),
|
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary.copy(0.52f)),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
@ -83,6 +83,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import androidx.core.graphics.get
|
import androidx.core.graphics.get
|
||||||
|
import androidx.lifecycle.distinctUntilChanged
|
||||||
import androidx.lifecycle.map
|
import androidx.lifecycle.map
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.compose.AsyncImagePainter
|
import coil.compose.AsyncImagePainter
|
||||||
@ -160,6 +161,8 @@ import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonBoxModifer
|
import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonBoxModifer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonIconButtonModifier
|
import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonIconButtonModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonIconModifier
|
import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonIconModifier
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size24Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size30Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size30Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size30dp
|
import com.vitorpamplona.amethyst.ui.theme.Size30dp
|
||||||
@ -168,12 +171,16 @@ import com.vitorpamplona.amethyst.ui.theme.Size55Modifier
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
|
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.UserNameMaxRowHeight
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.UserNameRowHeight
|
||||||
import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifier
|
import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
|
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import com.vitorpamplona.amethyst.ui.theme.replyBackground
|
import com.vitorpamplona.amethyst.ui.theme.replyBackground
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.repostProfileBorder
|
import com.vitorpamplona.amethyst.ui.theme.repostProfileBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
@ -195,7 +202,7 @@ import java.util.Locale
|
|||||||
fun NoteCompose(
|
fun NoteCompose(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
routeForLastRead: String? = null,
|
routeForLastRead: String? = null,
|
||||||
modifier: Modifier = remember { Modifier },
|
modifier: Modifier = Modifier,
|
||||||
isBoostedNote: Boolean = false,
|
isBoostedNote: Boolean = false,
|
||||||
isQuotedNote: Boolean = false,
|
isQuotedNote: Boolean = false,
|
||||||
unPackReply: Boolean = true,
|
unPackReply: Boolean = true,
|
||||||
@ -207,9 +214,10 @@ fun NoteCompose(
|
|||||||
) {
|
) {
|
||||||
val isBlank by baseNote.live().metadata.map {
|
val isBlank by baseNote.live().metadata.map {
|
||||||
it.note.event == null
|
it.note.event == null
|
||||||
}.observeAsState(baseNote.event == null)
|
}.distinctUntilChanged().observeAsState(baseNote.event == null)
|
||||||
|
|
||||||
if (isBlank) {
|
Crossfade(targetState = isBlank) {
|
||||||
|
if (it) {
|
||||||
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||||
BlankNote(
|
BlankNote(
|
||||||
remember {
|
remember {
|
||||||
@ -237,6 +245,7 @@ fun NoteCompose(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CheckHiddenNoteCompose(
|
fun CheckHiddenNoteCompose(
|
||||||
@ -261,7 +270,8 @@ fun CheckHiddenNoteCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isHidden) {
|
Crossfade(targetState = isHidden) {
|
||||||
|
if (!it) {
|
||||||
LoadedNoteCompose(
|
LoadedNoteCompose(
|
||||||
note,
|
note,
|
||||||
routeForLastRead,
|
routeForLastRead,
|
||||||
@ -277,6 +287,7 @@ fun CheckHiddenNoteCompose(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class NoteComposeReportState(
|
data class NoteComposeReportState(
|
||||||
@ -309,20 +320,52 @@ fun LoadedNoteCompose(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
WatchForReports(note, accountViewModel) { newIsAcceptable, newCanPreview, newRelevantReports ->
|
WatchForReports(note, accountViewModel) { newIsAcceptable, newCanPreview, newRelevantReports ->
|
||||||
if (newIsAcceptable != state.isAcceptable || newCanPreview != state.canPreview) {
|
if (newIsAcceptable != state.isAcceptable || newCanPreview != state.canPreview) {
|
||||||
|
scope.launch(Dispatchers.Main) {
|
||||||
state = NoteComposeReportState(newIsAcceptable, newCanPreview, newRelevantReports)
|
state = NoteComposeReportState(newIsAcceptable, newCanPreview, newRelevantReports)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Crossfade(targetState = state) {
|
||||||
|
RenderReportState(
|
||||||
|
it,
|
||||||
|
note,
|
||||||
|
routeForLastRead,
|
||||||
|
modifier,
|
||||||
|
isBoostedNote,
|
||||||
|
isQuotedNote,
|
||||||
|
unPackReply,
|
||||||
|
makeItShort,
|
||||||
|
addMarginTop,
|
||||||
|
parentBackgroundColor,
|
||||||
|
accountViewModel,
|
||||||
|
nav
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RenderReportState(
|
||||||
|
state: NoteComposeReportState,
|
||||||
|
note: Note,
|
||||||
|
routeForLastRead: String? = null,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
isBoostedNote: Boolean = false,
|
||||||
|
isQuotedNote: Boolean = false,
|
||||||
|
unPackReply: Boolean = true,
|
||||||
|
makeItShort: Boolean = false,
|
||||||
|
addMarginTop: Boolean = true,
|
||||||
|
parentBackgroundColor: MutableState<Color>? = null,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit
|
||||||
|
) {
|
||||||
var showReportedNote by remember { mutableStateOf(false) }
|
var showReportedNote by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val showHiddenNote by remember(state, showReportedNote) {
|
Crossfade(targetState = !state.isAcceptable && !showReportedNote) { showHiddenNote ->
|
||||||
derivedStateOf {
|
|
||||||
!state.isAcceptable && !showReportedNote
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showHiddenNote) {
|
if (showHiddenNote) {
|
||||||
HiddenNote(
|
HiddenNote(
|
||||||
state.relevantReports,
|
state.relevantReports,
|
||||||
@ -333,11 +376,7 @@ fun LoadedNoteCompose(
|
|||||||
onClick = { showReportedNote = true }
|
onClick = { showReportedNote = true }
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val canPreview by remember(state, showReportedNote) {
|
val canPreview = (!state.isAcceptable && showReportedNote) || state.canPreview
|
||||||
derivedStateOf {
|
|
||||||
(!state.isAcceptable && showReportedNote) || state.canPreview
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NormalNote(
|
NormalNote(
|
||||||
note,
|
note,
|
||||||
@ -355,6 +394,7 @@ fun LoadedNoteCompose(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WatchForReports(
|
fun WatchForReports(
|
||||||
@ -368,13 +408,23 @@ fun WatchForReports(
|
|||||||
LaunchedEffect(key1 = noteReportsState, key2 = userFollowsState) {
|
LaunchedEffect(key1 = noteReportsState, key2 = userFollowsState) {
|
||||||
launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
accountViewModel.account.let { loggedIn ->
|
accountViewModel.account.let { loggedIn ->
|
||||||
val newCanPreview = note.author?.pubkeyHex == loggedIn.userProfile().pubkeyHex ||
|
val isFromLoggedIn = note.author?.pubkeyHex == loggedIn.userProfile().pubkeyHex
|
||||||
(note.author?.let { loggedIn.userProfile().isFollowingCached(it) } ?: true) ||
|
val isFromLoggedInFollow = note.author?.let { loggedIn.userProfile().isFollowingCached(it) } ?: true
|
||||||
noteReportsState?.note?.hasAnyReports() != true
|
|
||||||
|
if (isFromLoggedIn || isFromLoggedInFollow) {
|
||||||
|
// No need to process if from trusted people
|
||||||
|
onChange(true, true, persistentSetOf())
|
||||||
|
} else {
|
||||||
|
val newCanPreview = noteReportsState?.note?.hasAnyReports() != true
|
||||||
|
|
||||||
val newIsAcceptable = noteReportsState?.note?.let {
|
val newIsAcceptable = noteReportsState?.note?.let {
|
||||||
loggedIn.isAcceptable(it)
|
loggedIn.isAcceptable(it)
|
||||||
} ?: true
|
} ?: true
|
||||||
|
|
||||||
|
if (newCanPreview && newIsAcceptable) {
|
||||||
|
// No need to process reports if nothing is wrong
|
||||||
|
onChange(true, true, persistentSetOf())
|
||||||
|
} else {
|
||||||
val newRelevantReports = noteReportsState?.note?.let {
|
val newRelevantReports = noteReportsState?.note?.let {
|
||||||
loggedIn.getRelevantReports(it)
|
loggedIn.getRelevantReports(it)
|
||||||
} ?: emptySet()
|
} ?: emptySet()
|
||||||
@ -384,6 +434,8 @@ fun WatchForReports(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NormalNote(
|
fun NormalNote(
|
||||||
@ -400,29 +452,18 @@ fun NormalNote(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val noteEvent = remember { baseNote.event }
|
when (baseNote.event) {
|
||||||
|
is ChannelCreateEvent, is ChannelMetadataEvent -> ChannelHeader(
|
||||||
val isChannelHeader by remember {
|
|
||||||
derivedStateOf {
|
|
||||||
(baseNote.event is ChannelCreateEvent || baseNote.event is ChannelMetadataEvent) && baseNote.channelHex() != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isChannelHeader) {
|
|
||||||
ChannelHeader(
|
|
||||||
channelNote = baseNote,
|
channelNote = baseNote,
|
||||||
showVideo = !makeItShort,
|
showVideo = !makeItShort,
|
||||||
showBottomDiviser = true,
|
showBottomDiviser = true,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav
|
nav = nav
|
||||||
)
|
)
|
||||||
} else if (noteEvent is BadgeDefinitionEvent) {
|
is BadgeDefinitionEvent -> BadgeDisplay(baseNote = baseNote)
|
||||||
BadgeDisplay(baseNote = baseNote)
|
is FileHeaderEvent -> FileHeaderDisplay(baseNote)
|
||||||
} else if (noteEvent is FileHeaderEvent) {
|
is FileStorageHeaderEvent -> FileStorageHeaderDisplay(baseNote)
|
||||||
FileHeaderDisplay(baseNote)
|
else ->
|
||||||
} else if (noteEvent is FileStorageHeaderEvent) {
|
|
||||||
FileStorageHeaderDisplay(baseNote)
|
|
||||||
} else {
|
|
||||||
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||||
CheckNewAndRenderNote(
|
CheckNewAndRenderNote(
|
||||||
baseNote,
|
baseNote,
|
||||||
@ -534,7 +575,7 @@ private fun ClickableNote(
|
|||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val updatedModifier = remember(backgroundColor.value) {
|
val updatedModifier = remember(backgroundColor) {
|
||||||
modifier
|
modifier
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = {
|
onClick = {
|
||||||
@ -569,17 +610,8 @@ fun InnerNoteWithReactions(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val notBoostedNorQuote by remember {
|
val notBoostedNorQuote = !isBoostedNote && !isQuotedNote
|
||||||
derivedStateOf {
|
val showSecondRow = baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent && !isBoostedNote && !isQuotedNote
|
||||||
!isBoostedNote && !isQuotedNote
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val showSecondRow by remember {
|
|
||||||
derivedStateOf {
|
|
||||||
baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent && !isBoostedNote && !isQuotedNote
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = remember {
|
modifier = remember {
|
||||||
@ -593,10 +625,13 @@ fun InnerNoteWithReactions(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (notBoostedNorQuote) {
|
if (notBoostedNorQuote) {
|
||||||
|
Column(WidthAuthorPictureModifier) {
|
||||||
AuthorAndRelayInformation(baseNote, accountViewModel, nav)
|
AuthorAndRelayInformation(baseNote, accountViewModel, nav)
|
||||||
|
}
|
||||||
Spacer(modifier = DoubleHorzSpacer)
|
Spacer(modifier = DoubleHorzSpacer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column(Modifier.fillMaxWidth()) {
|
||||||
NoteBody(
|
NoteBody(
|
||||||
baseNote = baseNote,
|
baseNote = baseNote,
|
||||||
showAuthorPicture = isQuotedNote,
|
showAuthorPicture = isQuotedNote,
|
||||||
@ -609,12 +644,9 @@ fun InnerNoteWithReactions(
|
|||||||
nav = nav
|
nav = nav
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val isNotRepost by remember {
|
val isNotRepost = baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent
|
||||||
derivedStateOf {
|
|
||||||
baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNotRepost) {
|
if (isNotRepost) {
|
||||||
if (makeItShort) {
|
if (makeItShort) {
|
||||||
@ -651,7 +683,6 @@ private fun NoteBody(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
Column(Modifier.fillMaxWidth()) {
|
|
||||||
FirstUserInfoRow(
|
FirstUserInfoRow(
|
||||||
baseNote = baseNote,
|
baseNote = baseNote,
|
||||||
showAuthorPicture = showAuthorPicture,
|
showAuthorPicture = showAuthorPicture,
|
||||||
@ -688,7 +719,6 @@ private fun NoteBody(
|
|||||||
nav
|
nav
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RenderNoteRow(
|
private fun RenderNoteRow(
|
||||||
@ -1711,6 +1741,15 @@ private fun ReplyRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (showReply) {
|
||||||
|
val replyingDirectlyTo = remember { note.replyTo?.lastOrNull() }
|
||||||
|
if (replyingDirectlyTo != null && unPackReply) {
|
||||||
|
ReplyNoteComposition(replyingDirectlyTo, backgroundColor, accountViewModel, nav)
|
||||||
|
Spacer(modifier = StdVertSpacer)
|
||||||
|
} else {
|
||||||
|
// ReplyInformation(note.replyTo, noteEvent.mentions(), accountViewModel, nav)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
val showChannelReply by remember {
|
val showChannelReply by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
(noteEvent is ChannelMessageEvent && (note.replyTo != null || noteEvent.hasAnyTaggedUser())) ||
|
(noteEvent is ChannelMessageEvent && (note.replyTo != null || noteEvent.hasAnyTaggedUser())) ||
|
||||||
@ -1718,15 +1757,7 @@ private fun ReplyRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showReply) {
|
if (showChannelReply) {
|
||||||
val replyingDirectlyTo = remember { note.replyTo?.lastOrNull() }
|
|
||||||
if (replyingDirectlyTo != null && unPackReply) {
|
|
||||||
ReplyNoteComposition(replyingDirectlyTo, backgroundColor, accountViewModel, nav)
|
|
||||||
Spacer(modifier = Modifier.height(5.dp))
|
|
||||||
} else {
|
|
||||||
// ReplyInformation(note.replyTo, noteEvent.mentions(), accountViewModel, nav)
|
|
||||||
}
|
|
||||||
} else if (showChannelReply) {
|
|
||||||
val channelHex = note.channelHex()
|
val channelHex = note.channelHex()
|
||||||
channelHex?.let {
|
channelHex?.let {
|
||||||
ChannelHeader(
|
ChannelHeader(
|
||||||
@ -1745,6 +1776,7 @@ private fun ReplyRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ReplyNoteComposition(
|
private fun ReplyNoteComposition(
|
||||||
@ -1759,7 +1791,7 @@ private fun ReplyNoteComposition(
|
|||||||
val defaultReplyBackground = MaterialTheme.colors.replyBackground
|
val defaultReplyBackground = MaterialTheme.colors.replyBackground
|
||||||
|
|
||||||
LaunchedEffect(key1 = backgroundColor.value, key2 = defaultReplyBackground) {
|
LaunchedEffect(key1 = backgroundColor.value, key2 = defaultReplyBackground) {
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.Default) {
|
||||||
val newReplyBackgroundColor =
|
val newReplyBackgroundColor =
|
||||||
defaultReplyBackground.compositeOver(backgroundColor.value)
|
defaultReplyBackground.compositeOver(backgroundColor.value)
|
||||||
if (replyBackgroundColor.value != newReplyBackgroundColor) {
|
if (replyBackgroundColor.value != newReplyBackgroundColor) {
|
||||||
@ -1768,22 +1800,10 @@ private fun ReplyNoteComposition(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val borderColor = MaterialTheme.colors.subtleBorder
|
|
||||||
|
|
||||||
NoteCompose(
|
NoteCompose(
|
||||||
baseNote = replyingDirectlyTo,
|
baseNote = replyingDirectlyTo,
|
||||||
isQuotedNote = true,
|
isQuotedNote = true,
|
||||||
modifier = remember {
|
modifier = MaterialTheme.colors.replyModifier,
|
||||||
Modifier
|
|
||||||
.padding(top = 5.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(shape = QuoteBorder)
|
|
||||||
.border(
|
|
||||||
1.dp,
|
|
||||||
borderColor,
|
|
||||||
QuoteBorder
|
|
||||||
)
|
|
||||||
},
|
|
||||||
unPackReply = false,
|
unPackReply = false,
|
||||||
makeItShort = true,
|
makeItShort = true,
|
||||||
parentBackgroundColor = replyBackgroundColor,
|
parentBackgroundColor = replyBackgroundColor,
|
||||||
@ -1801,7 +1821,7 @@ private fun SecondUserInfoRow(
|
|||||||
val noteEvent = remember { note.event } ?: return
|
val noteEvent = remember { note.event } ?: return
|
||||||
val noteAuthor = remember { note.author } ?: return
|
val noteAuthor = remember { note.author } ?: return
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = CenterVertically, modifier = UserNameMaxRowHeight) {
|
||||||
ObserveDisplayNip05Status(noteAuthor, remember { Modifier.weight(1f) })
|
ObserveDisplayNip05Status(noteAuthor, remember { Modifier.weight(1f) })
|
||||||
|
|
||||||
val baseReward = remember { noteEvent.getReward()?.let { Reward(it) } }
|
val baseReward = remember { noteEvent.getReward()?.let { Reward(it) } }
|
||||||
@ -1823,7 +1843,7 @@ private fun FirstUserInfoRow(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
Row(verticalAlignment = CenterVertically, modifier = remember { UserNameRowHeight }) {
|
||||||
val isRepost by remember {
|
val isRepost by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent
|
baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent
|
||||||
@ -1869,13 +1889,13 @@ private fun MoreOptionsButton(
|
|||||||
var moreActionsExpanded by remember { mutableStateOf(false) }
|
var moreActionsExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
modifier = remember { Modifier.size(24.dp) },
|
modifier = Size24Modifier,
|
||||||
onClick = { moreActionsExpanded = true }
|
onClick = { moreActionsExpanded = true }
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.MoreVert,
|
imageVector = Icons.Default.MoreVert,
|
||||||
null,
|
null,
|
||||||
modifier = remember { Modifier.size(15.dp) },
|
modifier = Size15Modifier,
|
||||||
tint = MaterialTheme.colors.placeholderText
|
tint = MaterialTheme.colors.placeholderText
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1908,7 +1928,6 @@ fun TimeAgo(time: Long) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AuthorAndRelayInformation(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
private fun AuthorAndRelayInformation(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
Column(WidthAuthorPictureModifier) {
|
|
||||||
// Draws the boosted picture outside the boosted card.
|
// Draws the boosted picture outside the boosted card.
|
||||||
Box(modifier = Size55Modifier, contentAlignment = Alignment.BottomEnd) {
|
Box(modifier = Size55Modifier, contentAlignment = Alignment.BottomEnd) {
|
||||||
RenderAuthorImages(baseNote, nav, accountViewModel)
|
RenderAuthorImages(baseNote, nav, accountViewModel)
|
||||||
@ -1916,7 +1935,6 @@ private fun AuthorAndRelayInformation(baseNote: Note, accountViewModel: AccountV
|
|||||||
|
|
||||||
BadgeBox(baseNote, accountViewModel, nav)
|
BadgeBox(baseNote, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun BadgeBox(
|
private fun BadgeBox(
|
||||||
@ -1950,11 +1968,7 @@ private fun RenderAuthorImages(
|
|||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
accountViewModel: AccountViewModel
|
accountViewModel: AccountViewModel
|
||||||
) {
|
) {
|
||||||
val isRepost by remember {
|
val isRepost = baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent
|
||||||
derivedStateOf {
|
|
||||||
baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NoteAuthorPicture(baseNote, nav, accountViewModel, Size55dp)
|
NoteAuthorPicture(baseNote, nav, accountViewModel, Size55dp)
|
||||||
|
|
||||||
@ -1962,11 +1976,7 @@ private fun RenderAuthorImages(
|
|||||||
RepostNoteAuthorPicture(baseNote, accountViewModel, nav)
|
RepostNoteAuthorPicture(baseNote, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isChannel by remember {
|
val isChannel = baseNote.event is ChannelMessageEvent && baseNote.channelHex() != null
|
||||||
derivedStateOf {
|
|
||||||
baseNote.event is ChannelMessageEvent && baseNote.channelHex() != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isChannel) {
|
if (isChannel) {
|
||||||
val baseChannelHex = remember { baseNote.channelHex() }
|
val baseChannelHex = remember { baseNote.channelHex() }
|
||||||
@ -2001,7 +2011,7 @@ fun LoadChannel(baseChannelHex: String, content: @Composable (Channel) -> Unit)
|
|||||||
private fun ChannelNotePicture(baseChannel: Channel) {
|
private fun ChannelNotePicture(baseChannel: Channel) {
|
||||||
val model by baseChannel.live.map {
|
val model by baseChannel.live.map {
|
||||||
it.channel.profilePicture()
|
it.channel.profilePicture()
|
||||||
}.observeAsState()
|
}.distinctUntilChanged().observeAsState()
|
||||||
|
|
||||||
val backgroundColor = MaterialTheme.colors.background
|
val backgroundColor = MaterialTheme.colors.background
|
||||||
|
|
||||||
@ -2879,7 +2889,10 @@ private fun RelayBadges(baseNote: Note, accountViewModel: AccountViewModel, nav:
|
|||||||
mutableStateOf(lazyRelayList.take(3).toImmutableList())
|
mutableStateOf(lazyRelayList.take(3).toImmutableList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
WatchRelayLists(baseNote) { relayList ->
|
WatchRelayLists(baseNote) { relayList ->
|
||||||
|
scope.launch(Dispatchers.Main) {
|
||||||
if (!equalImmutableLists(relayList, lazyRelayList)) {
|
if (!equalImmutableLists(relayList, lazyRelayList)) {
|
||||||
lazyRelayList = relayList
|
lazyRelayList = relayList
|
||||||
shortRelayList = relayList.take(3).toImmutableList()
|
shortRelayList = relayList.take(3).toImmutableList()
|
||||||
@ -2891,6 +2904,7 @@ private fun RelayBadges(baseNote: Note, accountViewModel: AccountViewModel, nav:
|
|||||||
showShowMore = nextShowMore
|
showShowMore = nextShowMore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(DoubleVertSpacer)
|
Spacer(DoubleVertSpacer)
|
||||||
|
|
||||||
@ -2982,12 +2996,14 @@ fun NoteAuthorPicture(
|
|||||||
) {
|
) {
|
||||||
val author by baseNote.live().metadata.map {
|
val author by baseNote.live().metadata.map {
|
||||||
it.note.author
|
it.note.author
|
||||||
}.observeAsState()
|
}.distinctUntilChanged().observeAsState(baseNote.author)
|
||||||
|
|
||||||
if (author == null) {
|
Crossfade(targetState = author) {
|
||||||
|
if (it == null) {
|
||||||
DisplayBlankAuthor(size, modifier)
|
DisplayBlankAuthor(size, modifier)
|
||||||
} else {
|
} else {
|
||||||
ClickableUserPicture(author!!, size, accountViewModel, modifier, onClick)
|
ClickableUserPicture(it, size, accountViewModel, modifier, onClick)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3111,16 +3127,24 @@ fun BaseUserPicture(
|
|||||||
|
|
||||||
val userProfile by baseUser.live().metadata.map {
|
val userProfile by baseUser.live().metadata.map {
|
||||||
it.user.profilePicture()
|
it.user.profilePicture()
|
||||||
}.observeAsState()
|
}.distinctUntilChanged().observeAsState(baseUser.profilePicture())
|
||||||
|
|
||||||
|
val myBoxModifier = remember {
|
||||||
|
Modifier.size(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
Crossfade(targetState = userProfile) {
|
||||||
|
Box(myBoxModifier, contentAlignment = TopEnd) {
|
||||||
PictureAndFollowingMark(
|
PictureAndFollowingMark(
|
||||||
userHex = userPubkey,
|
userHex = userPubkey,
|
||||||
userPicture = userProfile,
|
userPicture = it,
|
||||||
size = size,
|
size = size,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
accountViewModel = accountViewModel
|
accountViewModel = accountViewModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PictureAndFollowingMark(
|
fun PictureAndFollowingMark(
|
||||||
@ -3157,14 +3181,18 @@ fun PictureAndFollowingMark(
|
|||||||
private fun ObserveAndDisplayFollowingMark(userHex: String, iconSize: Dp, accountViewModel: AccountViewModel) {
|
private fun ObserveAndDisplayFollowingMark(userHex: String, iconSize: Dp, accountViewModel: AccountViewModel) {
|
||||||
val showFollowingMark by accountViewModel.userFollows.map {
|
val showFollowingMark by accountViewModel.userFollows.map {
|
||||||
it.user.isFollowingCached(userHex) || (userHex == accountViewModel.account.userProfile().pubkeyHex)
|
it.user.isFollowingCached(userHex) || (userHex == accountViewModel.account.userProfile().pubkeyHex)
|
||||||
}.observeAsState(
|
}.distinctUntilChanged().observeAsState(
|
||||||
accountViewModel.account.userProfile().isFollowingCached(userHex) || (userHex == accountViewModel.account.userProfile().pubkeyHex)
|
accountViewModel.account.userProfile().isFollowingCached(userHex) || (userHex == accountViewModel.account.userProfile().pubkeyHex)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (showFollowingMark) {
|
Crossfade(targetState = showFollowingMark) {
|
||||||
|
if (it) {
|
||||||
|
Box(contentAlignment = TopEnd) {
|
||||||
FollowingIcon(iconSize)
|
FollowingIcon(iconSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun FollowingIcon(iconSize: Dp) {
|
private fun FollowingIcon(iconSize: Dp) {
|
||||||
|
@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UserCompose(
|
fun UserCompose(
|
||||||
@ -38,9 +39,9 @@ fun UserCompose(
|
|||||||
modifier = overallModifier,
|
modifier = overallModifier,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
UserPicture(baseUser, 55.dp, accountViewModel = accountViewModel, nav = nav)
|
UserPicture(baseUser, Size55dp, accountViewModel = accountViewModel, nav = nav)
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(start = 10.dp).weight(1f)) {
|
Column(modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
UsernameDisplay(baseUser)
|
UsernameDisplay(baseUser)
|
||||||
}
|
}
|
||||||
@ -48,7 +49,7 @@ fun UserCompose(
|
|||||||
AboutDisplay(baseUser)
|
AboutDisplay(baseUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
Column(modifier = remember { Modifier.padding(start = 10.dp) }) {
|
||||||
UserActionOptions(baseUser, accountViewModel)
|
UserActionOptions(baseUser, accountViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package com.vitorpamplona.amethyst.ui.note
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.IconButton
|
import androidx.compose.material.IconButton
|
||||||
@ -20,13 +22,11 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
|
|||||||
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 androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.distinctUntilChanged
|
|
||||||
import androidx.lifecycle.map
|
import androidx.lifecycle.map
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.tts.TextToSpeechHelper
|
import com.vitorpamplona.amethyst.service.tts.TextToSpeechHelper
|
||||||
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdButtonSizeModifier
|
import com.vitorpamplona.amethyst.ui.theme.StdButtonSizeModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||||
@ -36,38 +36,34 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
|||||||
fun NoteUsernameDisplay(baseNote: Note, weight: Modifier = Modifier) {
|
fun NoteUsernameDisplay(baseNote: Note, weight: Modifier = Modifier) {
|
||||||
val authorState by baseNote.live().metadata.map {
|
val authorState by baseNote.live().metadata.map {
|
||||||
it.note.author
|
it.note.author
|
||||||
}.distinctUntilChanged().observeAsState()
|
}.observeAsState(baseNote.author)
|
||||||
|
|
||||||
authorState?.let {
|
Crossfade(targetState = authorState, modifier = weight) {
|
||||||
|
it?.let {
|
||||||
UsernameDisplay(it, weight)
|
UsernameDisplay(it, weight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UsernameDisplay(baseUser: User, weight: Modifier = Modifier) {
|
fun UsernameDisplay(baseUser: User, weight: Modifier = Modifier) {
|
||||||
val userState by baseUser.live().metadata.observeAsState()
|
|
||||||
val bestUserName by remember(userState) {
|
|
||||||
derivedStateOf {
|
|
||||||
userState?.user?.bestUsername()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val bestDisplayName by remember(userState) {
|
|
||||||
derivedStateOf {
|
|
||||||
userState?.user?.bestDisplayName()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val npubDisplay by remember {
|
val npubDisplay by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
baseUser.pubkeyDisplayHex()
|
baseUser.pubkeyDisplayHex()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val tags by remember(userState) {
|
|
||||||
derivedStateOf {
|
|
||||||
userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UserNameDisplay(bestUserName, bestDisplayName, npubDisplay, tags, weight)
|
val userMetadata by baseUser.live().metadata.map {
|
||||||
|
it.user.info
|
||||||
|
}.observeAsState(baseUser.info)
|
||||||
|
|
||||||
|
Crossfade(targetState = userMetadata, modifier = weight) {
|
||||||
|
if (it != null) {
|
||||||
|
UserNameDisplay(it.bestUsername(), it.bestDisplayName(), npubDisplay, it.tags, weight)
|
||||||
|
} else {
|
||||||
|
NPubDisplay(npubDisplay, weight)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -106,6 +102,7 @@ private fun UserDisplay(
|
|||||||
tags: ImmutableListOfLists<String>?,
|
tags: ImmutableListOfLists<String>?,
|
||||||
modifier: Modifier
|
modifier: Modifier
|
||||||
) {
|
) {
|
||||||
|
Row(modifier = modifier) {
|
||||||
CreateTextWithEmoji(
|
CreateTextWithEmoji(
|
||||||
text = bestDisplayName,
|
text = bestDisplayName,
|
||||||
tags = tags,
|
tags = tags,
|
||||||
@ -117,6 +114,7 @@ private fun UserDisplay(
|
|||||||
Spacer(StdHorzSpacer)
|
Spacer(StdHorzSpacer)
|
||||||
DrawPlayName(bestDisplayName)
|
DrawPlayName(bestDisplayName)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun UserAndUsernameDisplay(
|
private fun UserAndUsernameDisplay(
|
||||||
@ -125,6 +123,7 @@ private fun UserAndUsernameDisplay(
|
|||||||
bestUserName: String,
|
bestUserName: String,
|
||||||
modifier: Modifier
|
modifier: Modifier
|
||||||
) {
|
) {
|
||||||
|
Row(modifier = modifier) {
|
||||||
CreateTextWithEmoji(
|
CreateTextWithEmoji(
|
||||||
text = bestDisplayName,
|
text = bestDisplayName,
|
||||||
tags = tags,
|
tags = tags,
|
||||||
@ -142,6 +141,7 @@ private fun UserAndUsernameDisplay(
|
|||||||
Spacer(StdHorzSpacer)
|
Spacer(StdHorzSpacer)
|
||||||
DrawPlayName(bestDisplayName)
|
DrawPlayName(bestDisplayName)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DrawPlayName(name: String) {
|
fun DrawPlayName(name: String) {
|
||||||
|
@ -35,6 +35,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.ShowUserButton
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.UnfollowButton
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.UnfollowButton
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
|
||||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -106,7 +107,7 @@ private fun RenderZapNote(
|
|||||||
},
|
},
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
UserPicture(baseAuthor, 55.dp, accountViewModel = accountViewModel, nav = nav)
|
UserPicture(baseAuthor, Size55dp, accountViewModel = accountViewModel, nav = nav)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = remember {
|
modifier = remember {
|
||||||
|
@ -197,8 +197,7 @@ private fun FeedLoaded(
|
|||||||
) {
|
) {
|
||||||
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item ->
|
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item ->
|
||||||
val defaultModifier = remember {
|
val defaultModifier = remember {
|
||||||
Modifier
|
Modifier.fillMaxWidth().animateItemPlacement()
|
||||||
.fillMaxWidth().animateItemPlacement()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(defaultModifier) {
|
Row(defaultModifier) {
|
||||||
|
@ -586,9 +586,10 @@ fun ChannelHeader(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel.profilePicture()?.let {
|
||||||
RobohashAsyncImageProxy(
|
RobohashAsyncImageProxy(
|
||||||
robot = channel.idHex,
|
robot = channel.idHex,
|
||||||
model = channel.profilePicture(),
|
model = it,
|
||||||
contentDescription = stringResource(R.string.profile_image),
|
contentDescription = stringResource(R.string.profile_image),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(Size35dp)
|
.width(Size35dp)
|
||||||
@ -596,6 +597,7 @@ fun ChannelHeader(
|
|||||||
.padding(start = 10.dp)
|
.padding(start = 10.dp)
|
||||||
.clip(shape = CircleShape)
|
.clip(shape = CircleShape)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.theme
|
|||||||
import androidx.compose.foundation.layout.defaultMinSize
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.heightIn
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
@ -62,6 +63,7 @@ val StdPadding = Modifier.padding(10.dp)
|
|||||||
val Size15Modifier = Modifier.size(15.dp)
|
val Size15Modifier = Modifier.size(15.dp)
|
||||||
val Size20Modifier = Modifier.size(20.dp)
|
val Size20Modifier = Modifier.size(20.dp)
|
||||||
val Size22Modifier = Modifier.size(22.dp)
|
val Size22Modifier = Modifier.size(22.dp)
|
||||||
|
val Size24Modifier = Modifier.size(24.dp)
|
||||||
val Size30Modifier = Modifier.size(30.dp)
|
val Size30Modifier = Modifier.size(30.dp)
|
||||||
val Size55Modifier = Modifier.size(55.dp)
|
val Size55Modifier = Modifier.size(55.dp)
|
||||||
|
|
||||||
@ -76,6 +78,8 @@ val DiviserThickness = 0.25.dp
|
|||||||
|
|
||||||
val ReactionRowHeight = Modifier.height(24.dp).padding(start = 10.dp)
|
val ReactionRowHeight = Modifier.height(24.dp).padding(start = 10.dp)
|
||||||
val ReactionRowHeightChat = Modifier.height(25.dp)
|
val ReactionRowHeightChat = Modifier.height(25.dp)
|
||||||
|
val UserNameRowHeight = Modifier.height(22.dp).fillMaxWidth()
|
||||||
|
val UserNameMaxRowHeight = Modifier.heightIn(max = 22.dp).fillMaxWidth()
|
||||||
|
|
||||||
val Height4dpModifier = Modifier.height(4.dp)
|
val Height4dpModifier = Modifier.height(4.dp)
|
||||||
|
|
||||||
|
@ -121,6 +121,26 @@ val LightImageModifier = Modifier
|
|||||||
QuoteBorder
|
QuoteBorder
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val DarkReplyBorderModifier = Modifier
|
||||||
|
.padding(top = 5.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(shape = QuoteBorder)
|
||||||
|
.border(
|
||||||
|
1.dp,
|
||||||
|
DarkSubtleBorder,
|
||||||
|
QuoteBorder
|
||||||
|
)
|
||||||
|
|
||||||
|
val LightReplyBorderModifier = Modifier
|
||||||
|
.padding(top = 5.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(shape = QuoteBorder)
|
||||||
|
.border(
|
||||||
|
1.dp,
|
||||||
|
LightSubtleBorder,
|
||||||
|
QuoteBorder
|
||||||
|
)
|
||||||
|
|
||||||
val MarkDownStyleOnDark = richTextDefaults.copy(
|
val MarkDownStyleOnDark = richTextDefaults.copy(
|
||||||
paragraphSpacing = DefaultParagraphSpacing,
|
paragraphSpacing = DefaultParagraphSpacing,
|
||||||
headingStyle = DefaultHeadingStyle,
|
headingStyle = DefaultHeadingStyle,
|
||||||
@ -243,6 +263,9 @@ val Colors.repostProfileBorder: Modifier
|
|||||||
val Colors.imageModifier: Modifier
|
val Colors.imageModifier: Modifier
|
||||||
get() = if (isLight) LightImageModifier else DarkImageModifier
|
get() = if (isLight) LightImageModifier else DarkImageModifier
|
||||||
|
|
||||||
|
val Colors.replyModifier: Modifier
|
||||||
|
get() = if (isLight) LightReplyBorderModifier else DarkReplyBorderModifier
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AmethystTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
|
fun AmethystTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
|
||||||
val colors = if (darkTheme) {
|
val colors = if (darkTheme) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user