Minor updates to remember states in composition

This commit is contained in:
Vitor Pamplona 2023-06-07 12:26:32 -04:00
parent eaae672a30
commit 6a7d6a843d
4 changed files with 148 additions and 100 deletions

View File

@ -143,27 +143,46 @@ private fun RenderRegular(
}
}
val paragraphs = remember(content) {
content.split('\n').toImmutableList()
}
// FlowRow doesn't work well with paragraphs. So we need to split them
content.split('\n').forEach { paragraph ->
FlowRow() {
val s = remember(paragraph) {
if (isArabic(paragraph)) {
paragraph.trim().split(' ').reversed()
} else {
paragraph.trim().split(' ')
}
}
s.forEach { word: String ->
RenderWord(
word,
state,
canPreview,
backgroundColor,
accountViewModel,
nav,
tags
)
}
paragraphs.forEach { paragraph ->
RenderParagraph(paragraph, state, canPreview, backgroundColor, accountViewModel, nav, tags)
}
}
@Composable
@OptIn(ExperimentalLayoutApi::class)
private fun RenderParagraph(
paragraph: String,
state: RichTextViewerState,
canPreview: Boolean,
backgroundColor: Color,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
tags: ImmutableListOfLists<String>
) {
val s = remember(paragraph) {
if (isArabic(paragraph)) {
paragraph.trim().split(' ').reversed().toImmutableList()
} else {
paragraph.trim().split(' ').toImmutableList()
}
}
FlowRow() {
s.forEach { word: String ->
RenderWord(
word,
state,
canPreview,
backgroundColor,
accountViewModel,
nav,
tags
)
}
}
}
@ -863,13 +882,14 @@ fun HashTag(word: String, nav: (String) -> Unit) {
} ?: Text(text = "$word ")
}
data class LoadedTag(val user: User?, val note: Note?, val addedChars: String)
@Composable
fun TagLink(word: String, tags: ImmutableListOfLists<String>, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
var baseUserPair by remember { mutableStateOf<Pair<User, String?>?>(null) }
var baseNotePair by remember { mutableStateOf<Pair<Note, String?>?>(null) }
var loadedTag by remember { mutableStateOf<LoadedTag?>(null) }
LaunchedEffect(key1 = word) {
if (baseUserPair == null && baseNotePair == null) {
if (loadedTag == null) {
launch(Dispatchers.IO) {
val matcher = tagIndex.matcher(word)
val (index, suffix) = try {
@ -877,7 +897,7 @@ fun TagLink(word: String, tags: ImmutableListOfLists<String>, canPreview: Boolea
Pair(matcher.group(1)?.toInt(), matcher.group(2) ?: "")
} catch (e: Exception) {
Log.w("Tag Parser", "Couldn't link tag $word", e)
Pair(null, null)
Pair(null, "")
}
if (index != null && index >= 0 && index < tags.lists.size) {
@ -886,11 +906,11 @@ fun TagLink(word: String, tags: ImmutableListOfLists<String>, canPreview: Boolea
if (tag.size > 1) {
if (tag[0] == "p") {
LocalCache.checkGetOrCreateUser(tag[1])?.let {
baseUserPair = Pair(it, suffix)
loadedTag = LoadedTag(it, null, suffix)
}
} else if (tag[0] == "e" || tag[0] == "a") {
LocalCache.checkGetOrCreateNote(tag[1])?.let {
baseNotePair = Pair(it, suffix)
loadedTag = LoadedTag(null, it, suffix)
}
}
}
@ -899,55 +919,80 @@ fun TagLink(word: String, tags: ImmutableListOfLists<String>, canPreview: Boolea
}
}
baseUserPair?.let {
val innerUserState by it.first.live().metadata.observeAsState()
val displayName = remember(innerUserState) {
innerUserState?.user?.toBestDisplayName() ?: ""
}
val route = remember(innerUserState) {
"User/${it.first.pubkeyHex}"
}
val userTags = remember(innerUserState) {
innerUserState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists()
}
CreateClickableTextWithEmoji(
clickablePart = displayName,
suffix = remember { "${it.second} " },
tags = userTags,
route = route,
nav = nav
)
}
baseNotePair?.let {
if (canPreview) {
NoteCompose(
baseNote = it.first,
accountViewModel = accountViewModel,
modifier = Modifier
.padding(top = 2.dp, bottom = 0.dp, start = 0.dp, end = 0.dp)
.fillMaxWidth()
.clip(shape = RoundedCornerShape(15.dp))
.border(
1.dp,
MaterialTheme.colors.onSurface.copy(alpha = 0.12f),
RoundedCornerShape(15.dp)
),
parentBackgroundColor = backgroundColor,
isQuotedNote = true,
nav = nav
)
it.second?.ifBlank { null }?.let {
Text(text = "$it ")
if (loadedTag == null) {
Text(
text = remember {
"$word "
}
} else {
ClickableNoteTag(it.first, nav)
Text(text = "${it.second} ")
)
} else {
loadedTag?.user?.let {
DisplayUserFromTag(it, loadedTag?.addedChars ?: "", nav)
}
}
if (baseNotePair == null && baseUserPair == null) {
Text(text = "$word ")
loadedTag?.note?.let {
DisplayNoteFromTag(it, loadedTag?.addedChars ?: "", canPreview, accountViewModel, backgroundColor, nav)
}
}
}
@Composable
private fun DisplayNoteFromTag(
baseNote: Note,
addedChars: String,
canPreview: Boolean,
accountViewModel: AccountViewModel,
backgroundColor: Color,
nav: (String) -> Unit
) {
if (canPreview) {
NoteCompose(
baseNote = baseNote,
accountViewModel = accountViewModel,
modifier = Modifier
.padding(top = 2.dp, bottom = 0.dp, start = 0.dp, end = 0.dp)
.fillMaxWidth()
.clip(shape = RoundedCornerShape(15.dp))
.border(
1.dp,
MaterialTheme.colors.onSurface.copy(alpha = 0.12f),
RoundedCornerShape(15.dp)
),
parentBackgroundColor = backgroundColor,
isQuotedNote = true,
nav = nav
)
addedChars.ifBlank { null }?.let {
Text(text = remember { "$it " })
}
} else {
ClickableNoteTag(baseNote, nav)
Text(text = remember { "$addedChars " })
}
}
@Composable
private fun DisplayUserFromTag(
baseUser: User,
addedChars: String,
nav: (String) -> Unit
) {
val innerUserState by baseUser.live().metadata.observeAsState()
val displayName = remember(innerUserState) {
innerUserState?.user?.toBestDisplayName() ?: ""
}
val route = remember(innerUserState) {
"User/${baseUser.pubkeyHex}"
}
val userTags = remember(innerUserState) {
innerUserState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists()
}
CreateClickableTextWithEmoji(
clickablePart = displayName,
suffix = remember { "$addedChars " },
tags = userTags,
route = route,
nav = nav
)
}

View File

@ -39,7 +39,7 @@ abstract class AdditiveFeedFilter<T> : FeedFilter<T>() {
}
}
Log.d("Time", "${this.javaClass.simpleName} Additive Feed in $elapsed with ${feed.size} objects")
// Log.d("Time", "${this.javaClass.simpleName} Additive Feed in $elapsed with ${feed.size} objects")
return feed
}
}

View File

@ -65,12 +65,10 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
val baseNote = remember { multiSetCard.note }
var popupExpanded by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
var isNew by remember { mutableStateOf(false) }
LaunchedEffect(key1 = multiSetCard.createdAt()) {
LaunchedEffect(key1 = multiSetCard) {
launch(Dispatchers.IO) {
val newIsNew = multiSetCard.maxCreatedAt > NotificationCache.load(routeForLastRead)
@ -85,10 +83,14 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
val primaryColor = MaterialTheme.colors.newItemBackgroundColor
val defaultBackgroundColor = MaterialTheme.colors.background
val backgroundColor = if (isNew) {
primaryColor.compositeOver(defaultBackgroundColor)
} else {
defaultBackgroundColor
val backgroundColor by remember(isNew) {
derivedStateOf {
if (isNew) {
primaryColor.compositeOver(defaultBackgroundColor)
} else {
defaultBackgroundColor
}
}
}
val columnModifier = Modifier
@ -332,7 +334,7 @@ private fun AuthorPictureAndComment(
Box(modifier = remember { Modifier.size(35.dp) }, contentAlignment = Alignment.BottomCenter) {
FastNoteAuthorPicture(
author = author,
size = 35.dp,
size = remember { 35.dp },
accountViewModel = accountViewModel,
pictureModifier = authorPictureModifier
)
@ -380,10 +382,10 @@ fun AuthorGallery(
nav: (String) -> Unit,
accountViewModel: AccountViewModel
) {
Column(modifier = Modifier.padding(start = 10.dp)) {
Column(modifier = remember { Modifier.padding(start = 10.dp) }) {
FlowRow() {
authorNotes.forEach { note ->
Box(Modifier.size(35.dp)) {
Box(remember { Modifier.size(35.dp) }) {
NotePictureAndComment(note, backgroundColor, nav, accountViewModel)
}
}

View File

@ -154,7 +154,6 @@ import java.io.File
import java.math.BigDecimal
import java.net.URL
import java.util.Locale
import kotlin.time.ExperimentalTime
@OptIn(ExperimentalFoundationApi::class)
@Composable
@ -331,20 +330,21 @@ private fun WatchForReports(
onChange: (Boolean, Boolean, Set<Note>) -> Unit
) {
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = remember(accountState) { accountState?.account } ?: return
val noteReportsState by note.live().reports.observeAsState()
val noteForReports = remember(noteReportsState) { noteReportsState?.note } ?: return
LaunchedEffect(key1 = noteReportsState, key2 = accountState) {
launch(Dispatchers.Default) {
account.userProfile().let { loggedIn ->
val newCanPreview = note.author?.pubkeyHex == loggedIn.pubkeyHex ||
(note.author?.let { loggedIn.isFollowingCached(it) } ?: true) ||
!(noteForReports.hasAnyReports())
accountState?.account?.let { loggedIn ->
val newCanPreview = note.author?.pubkeyHex == loggedIn.userProfile().pubkeyHex ||
(note.author?.let { loggedIn.userProfile().isFollowingCached(it) } ?: true) ||
noteReportsState?.note?.hasAnyReports() != true
val newIsAcceptable = account.isAcceptable(noteForReports)
val newRelevantReports = account.getRelevantReports(noteForReports)
val newIsAcceptable = noteReportsState?.note?.let {
loggedIn.isAcceptable(it)
} ?: true
val newRelevantReports = noteReportsState?.note?.let {
loggedIn.getRelevantReports(it)
} ?: emptySet()
onChange(newIsAcceptable, newCanPreview, newRelevantReports)
}
@ -1489,11 +1489,11 @@ private fun FirstUserInfoRow(
Row(verticalAlignment = Alignment.CenterVertically) {
if (showAuthorPicture) {
NoteAuthorPicture(baseNote, nav, accountViewModel, 25.dp)
NoteAuthorPicture(baseNote, nav, accountViewModel, remember { 25.dp })
Spacer(padding)
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
} else {
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
}
if (eventNote is RepostEvent) {
@ -1560,7 +1560,6 @@ fun TimeAgo(time: Long) {
)
}
@OptIn(ExperimentalTime::class)
@Composable
private fun DrawAuthorImages(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
val baseChannelHex = remember { baseNote.channelHex() }
@ -1670,7 +1669,7 @@ private fun RepostNoteAuthorPicture(
baseNote = it,
nav = nav,
accountViewModel = accountViewModel,
size = 30.dp,
size = remember { 30.dp },
pictureModifier = Modifier.border(
2.dp,
MaterialTheme.colors.background,
@ -2511,6 +2510,8 @@ fun UserPicture(
.clip(shape = CircleShape)
}
val myIconSize = remember(size) { size.div(3.5f) }
Box(myBoxModifier, contentAlignment = TopEnd) {
RobohashAsyncImageProxy(
robot = userHex,
@ -2521,7 +2522,7 @@ fun UserPicture(
modifier = myImageModifier.background(MaterialTheme.colors.background)
)
ObserveAndDisplayFollowingMark(userHex, size.div(3.5f), accountViewModel)
ObserveAndDisplayFollowingMark(userHex, myIconSize, accountViewModel)
}
}