Fixes Poll Caching problems.
This commit is contained in:
@@ -1432,7 +1432,7 @@ fun RenderPoll(
|
|||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val noteEvent = note.event as? PollNoteEvent ?: return
|
val noteEvent = note.event as? PollNoteEvent ?: return
|
||||||
val eventContent = remember(note) { noteEvent.content() }
|
val eventContent = noteEvent.content()
|
||||||
|
|
||||||
if (makeItShort && accountViewModel.isLoggedUser(note.author)) {
|
if (makeItShort && accountViewModel.isLoggedUser(note.author)) {
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Popup
|
import androidx.compose.ui.window.Popup
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
@@ -101,7 +100,7 @@ fun PollNote(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val pollViewModel: PollNoteViewModel = viewModel(key = "PollNoteViewModel")
|
val pollViewModel: PollNoteViewModel = viewModel(key = "PollNoteViewModel${baseNote.idHex}")
|
||||||
|
|
||||||
pollViewModel.load(accountViewModel.account, baseNote)
|
pollViewModel.load(accountViewModel.account, baseNote)
|
||||||
|
|
||||||
@@ -126,11 +125,9 @@ fun PollNote(
|
|||||||
) {
|
) {
|
||||||
WatchZapsAndUpdateTallies(baseNote, pollViewModel)
|
WatchZapsAndUpdateTallies(baseNote, pollViewModel)
|
||||||
|
|
||||||
val tallies by pollViewModel.tallies.collectAsStateWithLifecycle()
|
pollViewModel.tallies.forEach { option ->
|
||||||
|
|
||||||
tallies.forEach { poll_op ->
|
|
||||||
OptionNote(
|
OptionNote(
|
||||||
poll_op,
|
option,
|
||||||
pollViewModel,
|
pollViewModel,
|
||||||
baseNote,
|
baseNote,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
@@ -167,9 +164,9 @@ private fun OptionNote(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier.padding(vertical = 3.dp),
|
modifier = Modifier.padding(vertical = 3.dp),
|
||||||
) {
|
) {
|
||||||
if (!pollViewModel.canZap()) {
|
if (!pollViewModel.canZap.value) {
|
||||||
val color =
|
val color =
|
||||||
if (poolOption.consensusThreadhold) {
|
if (poolOption.consensusThreadhold.value) {
|
||||||
Color.Green.copy(alpha = 0.32f)
|
Color.Green.copy(alpha = 0.32f)
|
||||||
} else {
|
} else {
|
||||||
MaterialTheme.colorScheme.mediumImportanceLink
|
MaterialTheme.colorScheme.mediumImportanceLink
|
||||||
@@ -181,8 +178,7 @@ private fun OptionNote(
|
|||||||
pollViewModel = pollViewModel,
|
pollViewModel = pollViewModel,
|
||||||
nonClickablePrepend = {
|
nonClickablePrepend = {
|
||||||
RenderOptionAfterVote(
|
RenderOptionAfterVote(
|
||||||
poolOption.descriptor,
|
poolOption,
|
||||||
poolOption.tally.toFloat(),
|
|
||||||
color,
|
color,
|
||||||
canPreview,
|
canPreview,
|
||||||
tags,
|
tags,
|
||||||
@@ -220,8 +216,7 @@ private fun OptionNote(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RenderOptionAfterVote(
|
private fun RenderOptionAfterVote(
|
||||||
description: String,
|
poolOption: PollOption,
|
||||||
totalRatio: Float,
|
|
||||||
color: Color,
|
color: Color,
|
||||||
canPreview: Boolean,
|
canPreview: Boolean,
|
||||||
tags: ImmutableListOfLists<String>,
|
tags: ImmutableListOfLists<String>,
|
||||||
@@ -229,10 +224,9 @@ private fun RenderOptionAfterVote(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val totalPercentage = remember(totalRatio) { "${(totalRatio * 100).roundToInt()}%" }
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
Modifier.fillMaxWidth(0.75f)
|
Modifier
|
||||||
|
.fillMaxWidth(0.75f)
|
||||||
.clip(shape = QuoteBorder)
|
.clip(shape = QuoteBorder)
|
||||||
.border(
|
.border(
|
||||||
2.dp,
|
2.dp,
|
||||||
@@ -243,7 +237,9 @@ private fun RenderOptionAfterVote(
|
|||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
modifier = Modifier.matchParentSize(),
|
modifier = Modifier.matchParentSize(),
|
||||||
color = color,
|
color = color,
|
||||||
progress = totalRatio,
|
progress = {
|
||||||
|
poolOption.tally.value.toFloat()
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
@@ -251,21 +247,31 @@ private fun RenderOptionAfterVote(
|
|||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.End,
|
horizontalAlignment = Alignment.End,
|
||||||
modifier = remember { Modifier.padding(horizontal = 10.dp).width(40.dp) },
|
modifier =
|
||||||
|
remember {
|
||||||
|
Modifier
|
||||||
|
.padding(horizontal = 10.dp)
|
||||||
|
.width(45.dp)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = totalPercentage,
|
text = "${(poolOption.tally.value.toFloat() * 100).roundToInt()}%",
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = remember { Modifier.fillMaxWidth().padding(15.dp) },
|
modifier =
|
||||||
|
remember {
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 15.dp, horizontal = 10.dp)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
TranslatableRichTextViewer(
|
TranslatableRichTextViewer(
|
||||||
description,
|
poolOption.descriptor,
|
||||||
canPreview,
|
canPreview,
|
||||||
remember { Modifier },
|
Modifier,
|
||||||
tags,
|
tags,
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
@@ -286,7 +292,8 @@ private fun RenderOptionBeforeVote(
|
|||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
Modifier.fillMaxWidth(0.75f)
|
Modifier
|
||||||
|
.fillMaxWidth(0.75f)
|
||||||
.clip(shape = QuoteBorder)
|
.clip(shape = QuoteBorder)
|
||||||
.border(
|
.border(
|
||||||
2.dp,
|
2.dp,
|
||||||
@@ -358,7 +365,7 @@ fun ZapVote(
|
|||||||
R.string.poll_unable_to_vote,
|
R.string.poll_unable_to_vote,
|
||||||
R.string.poll_author_no_vote,
|
R.string.poll_author_no_vote,
|
||||||
)
|
)
|
||||||
} else if (pollViewModel.isVoteAmountAtomic() && poolOption.zappedByLoggedIn) {
|
} else if (pollViewModel.isVoteAmountAtomic() && poolOption.zappedByLoggedIn.value) {
|
||||||
// only allow one vote per option when min==max, i.e. atomic vote amount specified
|
// only allow one vote per option when min==max, i.e. atomic vote amount specified
|
||||||
accountViewModel.toast(
|
accountViewModel.toast(
|
||||||
R.string.poll_unable_to_vote,
|
R.string.poll_unable_to_vote,
|
||||||
@@ -443,7 +450,7 @@ fun ZapVote(
|
|||||||
|
|
||||||
clickablePrepend()
|
clickablePrepend()
|
||||||
|
|
||||||
if (poolOption.zappedByLoggedIn) {
|
if (poolOption.zappedByLoggedIn.value) {
|
||||||
zappingProgress = 1f
|
zappingProgress = 1f
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Bolt,
|
imageVector = Icons.Default.Bolt,
|
||||||
@@ -471,8 +478,8 @@ fun ZapVote(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only show tallies after a user has zapped note
|
// only show tallies after a user has zapped note
|
||||||
if (!pollViewModel.canZap()) {
|
if (!pollViewModel.canZap.value) {
|
||||||
val amountStr = remember(poolOption.zappedValue) { showAmount(poolOption.zappedValue) }
|
val amountStr = remember(poolOption.zappedValue.value) { showAmount(poolOption.zappedValue.value) }
|
||||||
Text(
|
Text(
|
||||||
text = amountStr,
|
text = amountStr,
|
||||||
fontSize = Font14SP,
|
fontSize = Font14SP,
|
||||||
|
|||||||
@@ -20,8 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.note
|
package com.vitorpamplona.amethyst.ui.note
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
@@ -36,20 +37,18 @@ import com.vitorpamplona.quartz.events.VALUE_MAXIMUM
|
|||||||
import com.vitorpamplona.quartz.events.VALUE_MINIMUM
|
import com.vitorpamplona.quartz.events.VALUE_MINIMUM
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
|
|
||||||
@Immutable
|
@Stable
|
||||||
data class PollOption(
|
data class PollOption(
|
||||||
val option: Int,
|
val option: Int,
|
||||||
val descriptor: String,
|
val descriptor: String,
|
||||||
val zappedValue: BigDecimal,
|
var zappedValue: MutableState<BigDecimal> = mutableStateOf(BigDecimal.ZERO),
|
||||||
val tally: BigDecimal,
|
var tally: MutableState<BigDecimal> = mutableStateOf(BigDecimal.ZERO),
|
||||||
val consensusThreadhold: Boolean,
|
var consensusThreadhold: MutableState<Boolean> = mutableStateOf(false),
|
||||||
val zappedByLoggedIn: Boolean,
|
var zappedByLoggedIn: MutableState<Boolean> = mutableStateOf(false),
|
||||||
)
|
)
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
@@ -70,8 +69,8 @@ class PollNoteViewModel : ViewModel() {
|
|||||||
private var totalZapped: BigDecimal = BigDecimal.ZERO
|
private var totalZapped: BigDecimal = BigDecimal.ZERO
|
||||||
private var wasZappedByLoggedInAccount: Boolean = false
|
private var wasZappedByLoggedInAccount: Boolean = false
|
||||||
|
|
||||||
private val _tallies = MutableStateFlow<List<PollOption>>(emptyList())
|
var canZap = mutableStateOf(false)
|
||||||
val tallies = _tallies.asStateFlow()
|
var tallies: List<PollOption> = emptyList()
|
||||||
|
|
||||||
fun load(
|
fun load(
|
||||||
acc: Account,
|
acc: Account,
|
||||||
@@ -88,47 +87,44 @@ class PollNoteViewModel : ViewModel() {
|
|||||||
consensusThreshold =
|
consensusThreshold =
|
||||||
pollEvent?.getTagLong(CONSENSUS_THRESHOLD)?.toFloat()?.div(100)?.toBigDecimal()
|
pollEvent?.getTagLong(CONSENSUS_THRESHOLD)?.toFloat()?.div(100)?.toBigDecimal()
|
||||||
closedAt = pollEvent?.getTagLong(CLOSED_AT)
|
closedAt = pollEvent?.getTagLong(CLOSED_AT)
|
||||||
|
|
||||||
|
totalZapped = BigDecimal.ZERO
|
||||||
|
wasZappedByLoggedInAccount = false
|
||||||
|
|
||||||
|
canZap.value = checkIfCanZap()
|
||||||
|
|
||||||
|
tallies = pollOptions?.keys?.map { option ->
|
||||||
|
PollOption(
|
||||||
|
option,
|
||||||
|
pollOptions?.get(option) ?: "",
|
||||||
|
)
|
||||||
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshTallies() {
|
fun refreshTallies() {
|
||||||
viewModelScope.launch(Dispatchers.Default) {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
totalZapped = totalZapped()
|
totalZapped = totalZapped()
|
||||||
wasZappedByLoggedInAccount = false
|
wasZappedByLoggedInAccount = false
|
||||||
account?.calculateIfNoteWasZappedByAccount(pollNote) { wasZappedByLoggedInAccount = true }
|
account?.calculateIfNoteWasZappedByAccount(pollNote) {
|
||||||
|
wasZappedByLoggedInAccount = true
|
||||||
|
canZap.value = checkIfCanZap()
|
||||||
|
}
|
||||||
|
|
||||||
val newOptions =
|
tallies.forEach {
|
||||||
pollOptions?.keys?.map { option ->
|
it.zappedValue.value = zappedPollOptionAmount(it.option)
|
||||||
val zappedInOption = zappedPollOptionAmount(option)
|
it.tally.value =
|
||||||
|
if (totalZapped.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
val myTally =
|
it.zappedValue.value.divide(totalZapped, 2, RoundingMode.HALF_UP)
|
||||||
if (totalZapped.compareTo(BigDecimal.ZERO) > 0) {
|
} else {
|
||||||
zappedInOption.divide(totalZapped, 2, RoundingMode.HALF_UP)
|
BigDecimal.ZERO
|
||||||
} else {
|
}
|
||||||
BigDecimal.ZERO
|
it.consensusThreadhold.value = consensusThreshold != null && it.tally.value >= consensusThreshold!!
|
||||||
}
|
it.zappedByLoggedIn.value = account?.userProfile()?.let { it1 -> cachedIsPollOptionZappedBy(it.option, it1) } ?: false
|
||||||
|
}
|
||||||
val cachedZappedByLoggedIn =
|
|
||||||
account?.userProfile()?.let { it1 -> cachedIsPollOptionZappedBy(option, it1) } ?: false
|
|
||||||
|
|
||||||
val consensus = consensusThreshold != null && myTally >= consensusThreshold!!
|
|
||||||
|
|
||||||
PollOption(
|
|
||||||
option,
|
|
||||||
pollOptions?.get(option) ?: "",
|
|
||||||
zappedInOption,
|
|
||||||
myTally,
|
|
||||||
consensus,
|
|
||||||
cachedZappedByLoggedIn,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
_tallies.emit(
|
|
||||||
newOptions ?: emptyList(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun canZap(): Boolean {
|
fun checkIfCanZap(): Boolean {
|
||||||
val account = account ?: return false
|
val account = account ?: return false
|
||||||
val note = pollNote ?: return false
|
val note = pollNote ?: return false
|
||||||
return account.userProfile() != note.author && !wasZappedByLoggedInAccount
|
return account.userProfile() != note.author && !wasZappedByLoggedInAccount
|
||||||
|
|||||||
Reference in New Issue
Block a user