Separating Note observers into different types to avoid full screen refreshes.

This commit is contained in:
Vitor Pamplona
2023-01-25 18:54:20 -03:00
parent 542bd485d0
commit a9788cfa63
7 changed files with 43 additions and 45 deletions

View File

@@ -243,10 +243,12 @@ class Account(
fun joinChannel(idHex: String) { fun joinChannel(idHex: String) {
followingChannels.add(idHex) followingChannels.add(idHex)
invalidateData()
} }
fun leaveChannel(idHex: String) { fun leaveChannel(idHex: String) {
followingChannels.remove(idHex) followingChannels.remove(idHex)
invalidateData()
} }
fun hideUser(pubkeyHex: String) { fun hideUser(pubkeyHex: String) {

View File

@@ -45,7 +45,7 @@ class Note(val idHex: String) {
this.mentions = mentions this.mentions = mentions
this.replyTo = replyTo this.replyTo = replyTo
invalidateData() invalidateData(live)
} }
fun formattedDateTime(timestamp: Long): String { fun formattedDateTime(timestamp: Long): String {
@@ -77,22 +77,22 @@ class Note(val idHex: String) {
fun addReply(note: Note) { fun addReply(note: Note) {
if (replies.add(note)) if (replies.add(note))
invalidateData() invalidateData(liveReplies)
} }
fun addBoost(note: Note) { fun addBoost(note: Note) {
if (boosts.add(note)) if (boosts.add(note))
invalidateData() invalidateData(liveBoosts)
} }
fun addReaction(note: Note) { fun addReaction(note: Note) {
if (reactions.add(note)) if (reactions.add(note))
invalidateData() invalidateData(liveReactions)
} }
fun addReport(note: Note) { fun addReport(note: Note) {
if (reports.add(note)) if (reports.add(note))
invalidateData() invalidateData(liveReports)
} }
fun isReactedBy(user: User): Boolean { fun isReactedBy(user: User): Boolean {
@@ -110,10 +110,15 @@ class Note(val idHex: String) {
// Observers line up here. // Observers line up here.
val live: NoteLiveData = NoteLiveData(this) val live: NoteLiveData = NoteLiveData(this)
val liveReactions: NoteLiveData = NoteLiveData(this)
val liveBoosts: NoteLiveData = NoteLiveData(this)
val liveReplies: NoteLiveData = NoteLiveData(this)
val liveReports: NoteLiveData = NoteLiveData(this)
// Refreshes observers in batches. // Refreshes observers in batches.
var handlerWaiting = false var handlerWaiting = false
@Synchronized @Synchronized
fun invalidateData() { fun invalidateData(live: NoteLiveData) {
if (handlerWaiting) return if (handlerWaiting) return
handlerWaiting = true handlerWaiting = true

View File

@@ -14,13 +14,12 @@ import com.vitorpamplona.amethyst.ui.note.toShortenHex
@Composable @Composable
fun ClickableNoteTag( fun ClickableNoteTag(
note: Note, baesNote: Note,
navController: NavController navController: NavController
) { ) {
val innerNoteState by note.live.observeAsState()
ClickableText( ClickableText(
text = AnnotatedString("@${innerNoteState?.note?.id?.toNote()?.toShortenHex()} "), text = AnnotatedString("@${baesNote.id.toNote().toShortenHex()} "),
onClick = { navController.navigate("Note/${innerNoteState?.note?.idHex}") }, onClick = { navController.navigate("Note/${baesNote.idHex}") },
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary) style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
) )
} }

View File

@@ -186,7 +186,7 @@ fun NoteCompose(baseNote: Note, modifier: Modifier = Modifier, isInnerNote: Bool
RichTextViewer(eventContent, note.event?.tags, navController) RichTextViewer(eventContent, note.event?.tags, navController)
if (note.event !is ChannelMessageEvent) { if (note.event !is ChannelMessageEvent) {
ReactionsRowState(note, accountViewModel) ReactionsRow(note, accountViewModel)
} }
Divider( Divider(

View File

@@ -1,6 +1,5 @@
package com.vitorpamplona.amethyst.ui.note package com.vitorpamplona.amethyst.ui.note
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -21,6 +20,7 @@ import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@@ -44,7 +44,19 @@ import com.vitorpamplona.amethyst.ui.actions.NewPostView
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable @Composable
fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewModel) { fun ReactionsRow(baseNote: Note, accountViewModel: AccountViewModel) {
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = accountState?.account ?: return
val reactionsState by baseNote.liveReactions.observeAsState()
val reactedNote = reactionsState?.note
val boostsState by baseNote.liveBoosts.observeAsState()
val boostedNote = boostsState?.note
val repliesState by baseNote.liveReplies.observeAsState()
val replies = repliesState?.note?.replies ?: emptySet()
val grayTint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) val grayTint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
var popupExpanded by remember { mutableStateOf(false) } var popupExpanded by remember { mutableStateOf(false) }
@@ -65,7 +77,7 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
) { ) {
IconButton( IconButton(
modifier = Modifier.then(Modifier.size(24.dp)), modifier = Modifier.then(Modifier.size(24.dp)),
onClick = { if (account.isWriteable()) wantsToReplyTo = note } onClick = { if (account.isWriteable()) wantsToReplyTo = baseNote }
) { ) {
Icon( Icon(
painter = painterResource(R.drawable.ic_comment), painter = painterResource(R.drawable.ic_comment),
@@ -76,7 +88,7 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
} }
Text( Text(
" ${showCount(note.replies?.size)}", " ${showCount(replies.size)}",
fontSize = 14.sp, fontSize = 14.sp,
color = grayTint, color = grayTint,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
@@ -84,9 +96,9 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
IconButton( IconButton(
modifier = Modifier.then(Modifier.size(24.dp)), modifier = Modifier.then(Modifier.size(24.dp)),
onClick = { if (account.isWriteable()) accountViewModel.boost(note) } onClick = { if (account.isWriteable()) accountViewModel.boost(baseNote) }
) { ) {
if (note.isBoostedBy(account.userProfile())) { if (boostedNote?.isBoostedBy(account.userProfile()) == true) {
Icon( Icon(
painter = painterResource(R.drawable.ic_retweeted), painter = painterResource(R.drawable.ic_retweeted),
null, null,
@@ -104,7 +116,7 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
} }
Text( Text(
" ${showCount(note.boosts?.size)}", " ${showCount(boostedNote?.boosts?.size)}",
fontSize = 14.sp, fontSize = 14.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
@@ -112,9 +124,9 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
IconButton( IconButton(
modifier = Modifier.then(Modifier.size(24.dp)), modifier = Modifier.then(Modifier.size(24.dp)),
onClick = { if (account.isWriteable()) accountViewModel.reactTo(note) } onClick = { if (account.isWriteable()) accountViewModel.reactTo(baseNote) }
) { ) {
if (note.isReactedBy(account.userProfile())) { if (reactedNote?.isReactedBy(account.userProfile()) == true) {
Icon( Icon(
painter = painterResource(R.drawable.ic_liked), painter = painterResource(R.drawable.ic_liked),
null, null,
@@ -132,7 +144,7 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
} }
Text( Text(
" ${showCount(note.reactions?.size)}", " ${showCount(reactedNote?.reactions?.size)}",
fontSize = 14.sp, fontSize = 14.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
@@ -154,7 +166,7 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
Row(modifier = Modifier.weight(1f)) { Row(modifier = Modifier.weight(1f)) {
AsyncImage( AsyncImage(
model = ImageRequest.Builder(LocalContext.current) model = ImageRequest.Builder(LocalContext.current)
.data("https://counter.amethyst.social/${note.idHex}.svg?label=+&color=00000000") .data("https://counter.amethyst.social/${baseNote.idHex}.svg?label=+&color=00000000")
.crossfade(true) .crossfade(true)
.diskCachePolicy(CachePolicy.DISABLED) .diskCachePolicy(CachePolicy.DISABLED)
.memoryCachePolicy(CachePolicy.ENABLED) .memoryCachePolicy(CachePolicy.ENABLED)
@@ -179,7 +191,7 @@ fun ReactionsRow(note: Note, account: Account, accountViewModel: AccountViewMode
} }
} }
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel) NoteDropDownMenu(baseNote, popupExpanded, { popupExpanded = false }, accountViewModel)
} }
fun showCount(size: Int?): String { fun showCount(size: Int?): String {

View File

@@ -1,20 +0,0 @@
package com.vitorpamplona.amethyst.ui.note
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
fun ReactionsRowState(baseNote: Note, accountViewModel: AccountViewModel) {
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = accountState?.account
val noteState by baseNote.live.observeAsState()
val note = noteState?.note
if (account == null || note == null) return
ReactionsRow(note, account, accountViewModel)
}

View File

@@ -40,7 +40,7 @@ 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.NoteCompose import com.vitorpamplona.amethyst.ui.note.NoteCompose
import com.vitorpamplona.amethyst.ui.note.ReactionsRowState import com.vitorpamplona.amethyst.ui.note.ReactionsRow
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.ui.note.timeAgoLong import com.vitorpamplona.amethyst.ui.note.timeAgoLong
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -205,7 +205,7 @@ fun NoteMaster(baseNote: Note, accountViewModel: AccountViewModel, navController
if (eventContent != null) if (eventContent != null)
RichTextViewer(eventContent, note.event?.tags, navController) RichTextViewer(eventContent, note.event?.tags, navController)
ReactionsRowState(note, accountViewModel) ReactionsRow(note, accountViewModel)
Divider( Divider(
modifier = Modifier.padding(top = 10.dp), modifier = Modifier.padding(top = 10.dp),