From 12a1c3fe6d0683e6f0d7d33ea57bcd73ec2e7151 Mon Sep 17 00:00:00 2001 From: toadlyBroodle Date: Sat, 25 Mar 2023 15:46:54 +0900 Subject: [PATCH] add option tally percentage bars, create new PollNoteViewModel for each PollNote, fix isVoteAmountAtomic to directly launch wallet --- .../amethyst/ui/note/PollNote.kt | 36 ++++++++++++------- .../amethyst/ui/note/PollNoteViewModel.kt | 34 +++++++++++++----- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt index 4a119d44f..0f0f9c3ab 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note @@ -44,21 +43,19 @@ fun PollNote( accountViewModel: AccountViewModel, navController: NavController ) { - val pollViewModel: PollNoteViewModel = viewModel() + val pollViewModel = PollNoteViewModel() pollViewModel.load(note) pollViewModel.pollEvent?.pollOptions()?.forEach { poll_op -> Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() + verticalAlignment = Alignment.CenterVertically ) { TranslateableRichTextViewer( poll_op.value, canPreview, modifier = Modifier .width(250.dp) - .border(BorderStroke(1.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.32f))) - .padding(4.dp), + .border(BorderStroke(1.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.32f))), pollViewModel.pollEvent?.tags(), backgroundColor, accountViewModel, @@ -67,6 +64,18 @@ fun PollNote( ZapVote(note, accountViewModel, pollViewModel, poll_op.key) } + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + // only show tallies after user has zapped note + if (note.isZappedBy(accountViewModel.userProfile())) { + LinearProgressIndicator( + modifier = Modifier.width(250.dp), + progress = pollViewModel.optionVoteTally(poll_op.key) + ) + } + } } } @@ -119,7 +128,7 @@ fun ZapVote( ) .show() } - } else if (pollViewModel.isVoteAmountAtomic) { + } else if (pollViewModel.isVoteAmountAtomic()) { accountViewModel.zap( baseNote, pollViewModel.valueMaximum!!.toLong() * 1000, @@ -174,6 +183,7 @@ fun ZapVote( } } + // only show tallies after a user has zapped note if (zappedNote?.isZappedBy(account.userProfile()) == true) { Text( showAmount(zappedNote.zappedPollOptionAmount(pollOption)), @@ -196,7 +206,7 @@ fun ZapVoteAmountChoicePopup( ) { val context = LocalContext.current - var textAmount by rememberSaveable { mutableStateOf("") } + var inputAmountText by rememberSaveable { mutableStateOf("") } val colorInValid = TextFieldDefaults.outlinedTextFieldColors( focusedBorderColor = MaterialTheme.colors.error, @@ -221,14 +231,14 @@ fun ZapVoteAmountChoicePopup( modifier = Modifier .padding(10.dp) ) { - val amount = pollViewModel.amount(textAmount) + val amount = pollViewModel.inputAmountLong(inputAmountText) OutlinedTextField( - value = textAmount, - onValueChange = { textAmount = it }, + value = inputAmountText, + onValueChange = { inputAmountText = it }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.width(150.dp), - colors = if (pollViewModel.isValidAmount(amount)) colorValid else colorInValid, + colors = if (pollViewModel.isValidInputAmount(amount)) colorValid else colorInValid, label = { Text( text = stringResource(R.string.poll_zap_amount), @@ -245,7 +255,7 @@ fun ZapVoteAmountChoicePopup( Button( modifier = Modifier.padding(horizontal = 3.dp), - enabled = pollViewModel.isValidAmount(amount), + enabled = pollViewModel.isValidInputAmount(amount), onClick = { if (amount != null) { accountViewModel.zap( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt index 89b9bbe92..2c4a04df4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt @@ -1,24 +1,25 @@ package com.vitorpamplona.amethyst.ui.note -import androidx.lifecycle.ViewModel import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.model.* import java.util.* -class PollNoteViewModel : ViewModel() { +class PollNoteViewModel { var account: Account? = null - var pollNote: Note? = null + private var pollNote: Note? = null var pollEvent: PollNoteEvent? = null + private var pollOptions: Map? = null var valueMaximum: Int? = null - var valueMinimum: Int? = null - var closedAt: Int? = null - var consensusThreshold: Int? = null + private var valueMinimum: Int? = null + private var closedAt: Int? = null + private var consensusThreshold: Int? = null fun load(note: Note?) { pollNote = note pollEvent = pollNote?.event as PollNoteEvent + pollOptions = pollEvent?.pollOptions() valueMaximum = pollEvent?.getTagInt(VALUE_MAXIMUM) valueMinimum = pollEvent?.getTagInt(VALUE_MINIMUM) consensusThreshold = pollEvent?.getTagInt(CONSENSUS_THRESHOLD) @@ -29,7 +30,7 @@ class PollNoteViewModel : ViewModel() { pollNote?.createdAt()?.plus(it * (86400 + 120))!! > Date().time / 1000 } == true - val isVoteAmountAtomic = valueMaximum != null && valueMinimum != null && valueMinimum == valueMaximum + fun isVoteAmountAtomic(): Boolean = valueMaximum != null && valueMinimum != null && valueMinimum == valueMaximum fun voteAmountPlaceHolderText(sats: String): String = if (valueMinimum == null && valueMaximum == null) { sats @@ -41,13 +42,13 @@ class PollNoteViewModel : ViewModel() { "$valueMinimum—$valueMaximum $sats" } - fun amount(textAmount: String) = if (textAmount.isEmpty()) { null } else { + fun inputAmountLong(textAmount: String) = if (textAmount.isEmpty()) { null } else { try { textAmount.toLong() } catch (e: Exception) { null } } - fun isValidAmount(amount: Long?): Boolean { + fun isValidInputAmount(amount: Long?): Boolean { if (amount == null) { return false } else if (valueMinimum == null && valueMaximum == null) { @@ -69,4 +70,19 @@ class PollNoteViewModel : ViewModel() { } return false } + + fun optionVoteTally(op: Int): Float { + val tally = pollNote?.zappedPollOptionAmount(op)?.toFloat()?.div(zappedVoteTotal()) ?: 0f + return if (tally.isNaN()) { // catch div by 0 + 0f + } else { tally } + } + + private fun zappedVoteTotal(): Float { + var total = 0f + pollOptions?.keys?.forEach { + total += pollNote?.zappedPollOptionAmount(it)?.toFloat() ?: 0f + } + return total + } }