move PollNote logic to PollNoteViewModel,

fix PollNoteEvent tag getter funs for the final fucking time (hopefully)!,
only show option amounts if user has zapped poll note,
make poll options wider
This commit is contained in:
toadlyBroodle
2023-03-25 08:59:11 +09:00
parent 712c8ab2dd
commit 9b9cc092dc
3 changed files with 112 additions and 78 deletions
@@ -36,17 +36,20 @@ class PollNoteEvent(
.forEach { map[it[1].toInt()] = it[2] } .forEach { map[it[1].toInt()] = it[2] }
return map return map
} }
fun valueMaximum(): Int? = tags.filter { it.firstOrNull() == VALUE_MAXIMUM }
.getOrNull(1)?.getOrNull(1)?.toInt()
fun valueMinimum(): Int? = tags.filter { it.firstOrNull() == VALUE_MINIMUM } fun getTagInt(property: String): Int? {
.getOrNull(1)?.getOrNull(1)?.toInt() val tagList = tags.filter {
it.firstOrNull() == property
}
val tag = tagList.getOrNull(0)
val s = tag?.getOrNull(1)
fun consensusThreshold(): Int? = tags.filter { it.firstOrNull() == CONSENSUS_THRESHOLD } return if (s.isNullOrBlank() || s == "null") {
.getOrNull(1)?.getOrNull(1)?.toInt() null
} else {
fun closedAt(): Int? = tags.filter { it.firstOrNull() == CLOSED_AT } s.toInt()
.getOrNull(1)?.getOrNull(1)?.toInt() }
}
companion object { companion object {
const val kind = 6969 const val kind = 6969
@@ -26,10 +26,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
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.service.model.PollNoteEvent
import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
@@ -44,10 +44,10 @@ fun PollNote(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
navController: NavController navController: NavController
) { ) {
val pollEvent = note.event as PollNoteEvent val pollViewModel: PollNoteViewModel = viewModel()
val consensusThreshold = pollEvent.consensusThreshold() pollViewModel.load(note)
pollEvent.pollOptions().forEach { poll_op -> pollViewModel.pollEvent?.pollOptions()?.forEach { poll_op ->
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
@@ -56,16 +56,16 @@ fun PollNote(
poll_op.value, poll_op.value,
canPreview, canPreview,
modifier = Modifier modifier = Modifier
.weight(1f) .width(250.dp)
.border(BorderStroke(1.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.32f))) .border(BorderStroke(1.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.32f)))
.padding(4.dp), .padding(4.dp),
pollEvent.tags(), pollViewModel.pollEvent?.tags(),
backgroundColor, backgroundColor,
accountViewModel, accountViewModel,
navController navController
) )
ZapVote(note, accountViewModel, poll_op.key) ZapVote(note, accountViewModel, pollViewModel, poll_op.key)
} }
} }
} }
@@ -75,6 +75,7 @@ fun PollNote(
fun ZapVote( fun ZapVote(
baseNote: Note, baseNote: Note,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
pollViewModel: PollNoteViewModel,
pollOption: Int, pollOption: Int,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
@@ -89,15 +90,6 @@ fun ZapVote(
val context = LocalContext.current val context = LocalContext.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val pollEvent = baseNote.event as PollNoteEvent
val valueMaximum = pollEvent.valueMaximum()
val valueMinimum = pollEvent.valueMinimum()
val isPollClosed: Boolean = pollEvent.closedAt()?.let { // allow 2 minute leeway for zap to propagate
baseNote.createdAt()?.plus(it * (86400 + 120))!! > Date().time / 1000
} == true
val isVoteAmountAtomic = valueMaximum != null && valueMinimum != null && valueMinimum == valueMaximum
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
@@ -117,7 +109,7 @@ fun ZapVote(
) )
.show() .show()
} }
} else if (isPollClosed) { } else if (pollViewModel.isPollClosed) {
scope.launch { scope.launch {
Toast Toast
.makeText( .makeText(
@@ -127,10 +119,10 @@ fun ZapVote(
) )
.show() .show()
} }
} else if (isVoteAmountAtomic) { } else if (pollViewModel.isVoteAmountAtomic) {
accountViewModel.zap( accountViewModel.zap(
baseNote, baseNote,
valueMaximum!!.toLong() * 1000, pollViewModel.valueMaximum!!.toLong() * 1000,
pollOption, pollOption,
"", "",
context context
@@ -152,9 +144,8 @@ fun ZapVote(
ZapVoteAmountChoicePopup( ZapVoteAmountChoicePopup(
baseNote, baseNote,
accountViewModel, accountViewModel,
pollViewModel,
pollOption, pollOption,
valueMinimum,
valueMaximum,
onDismiss = { onDismiss = {
wantsToZap = false wantsToZap = false
}, },
@@ -183,12 +174,14 @@ fun ZapVote(
} }
} }
Text( if (zappedNote?.isZappedBy(account.userProfile()) == true) {
showAmount(zappedNote?.zappedPollOptionAmount(pollOption)), Text(
fontSize = 14.sp, showAmount(zappedNote.zappedPollOptionAmount(pollOption)),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), fontSize = 14.sp,
modifier = modifier color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
) modifier = modifier
)
}
} }
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@@ -196,9 +189,8 @@ fun ZapVote(
fun ZapVoteAmountChoicePopup( fun ZapVoteAmountChoicePopup(
baseNote: Note, baseNote: Note,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
pollViewModel: PollNoteViewModel,
pollOption: Int, pollOption: Int,
valueMinimum: Int?,
valueMaximum: Int?,
onDismiss: () -> Unit, onDismiss: () -> Unit,
onError: (text: String) -> Unit onError: (text: String) -> Unit
) { ) {
@@ -206,43 +198,6 @@ fun ZapVoteAmountChoicePopup(
var textAmount by rememberSaveable { mutableStateOf("") } var textAmount by rememberSaveable { mutableStateOf("") }
val placeHolderText = if (valueMinimum == null && valueMaximum == null) {
stringResource(R.string.sats)
} else if (valueMinimum == null) {
"1—$valueMaximum " + stringResource(R.string.sats)
} else if (valueMaximum == null) {
">$valueMinimum " + stringResource(R.string.sats)
} else {
"$valueMinimum$valueMaximum " + stringResource(R.string.sats)
}
val amount = if (textAmount.isEmpty()) { null } else {
try {
textAmount.toLong()
} catch (e: Exception) { null }
}
var isValidAmount = false
if (amount == null) {
isValidAmount = false
} else if (valueMinimum == null && valueMaximum == null) {
if (amount > 0) {
isValidAmount = true
}
} else if (valueMinimum == null) {
if (amount > 0 && amount <= valueMaximum!!) {
isValidAmount = true
}
} else if (valueMaximum == null) {
if (amount >= valueMinimum) {
isValidAmount = true
}
} else {
if ((valueMinimum <= amount) && (amount <= valueMaximum)) {
isValidAmount = true
}
}
val colorInValid = TextFieldDefaults.outlinedTextFieldColors( val colorInValid = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = MaterialTheme.colors.error, focusedBorderColor = MaterialTheme.colors.error,
unfocusedBorderColor = Color.Red unfocusedBorderColor = Color.Red
@@ -266,12 +221,14 @@ fun ZapVoteAmountChoicePopup(
modifier = Modifier modifier = Modifier
.padding(10.dp) .padding(10.dp)
) { ) {
val amount = pollViewModel.amount(textAmount)
OutlinedTextField( OutlinedTextField(
value = textAmount, value = textAmount,
onValueChange = { textAmount = it }, onValueChange = { textAmount = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
modifier = Modifier.width(150.dp), modifier = Modifier.width(150.dp),
colors = if (isValidAmount) colorValid else colorInValid, colors = if (pollViewModel.isValidAmount(amount)) colorValid else colorInValid,
label = { label = {
Text( Text(
text = stringResource(R.string.poll_zap_amount), text = stringResource(R.string.poll_zap_amount),
@@ -280,7 +237,7 @@ fun ZapVoteAmountChoicePopup(
}, },
placeholder = { placeholder = {
Text( Text(
text = placeHolderText, text = pollViewModel.voteAmountPlaceHolderText(context),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
) )
} }
@@ -288,7 +245,7 @@ fun ZapVoteAmountChoicePopup(
Button( Button(
modifier = Modifier.padding(horizontal = 3.dp), modifier = Modifier.padding(horizontal = 3.dp),
enabled = isValidAmount, enabled = pollViewModel.isValidAmount(amount),
onClick = { onClick = {
if (amount != null) { if (amount != null) {
accountViewModel.zap( accountViewModel.zap(
@@ -0,0 +1,74 @@
package com.vitorpamplona.amethyst.ui.note
import android.content.Context
import androidx.lifecycle.ViewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.*
import java.util.*
class PollNoteViewModel : ViewModel() {
var account: Account? = null
var pollNote: Note? = null
var pollEvent: PollNoteEvent? = null
var valueMaximum: Int? = null
var valueMinimum: Int? = null
var closedAt: Int? = null
var consensusThreshold: Int? = null
fun load(note: Note?) {
pollNote = note
pollEvent = pollNote?.event as PollNoteEvent
valueMaximum = pollEvent?.getTagInt(VALUE_MAXIMUM)
valueMinimum = pollEvent?.getTagInt(VALUE_MINIMUM)
consensusThreshold = pollEvent?.getTagInt(CONSENSUS_THRESHOLD)
closedAt = pollEvent?.getTagInt(CLOSED_AT)
}
val isPollClosed: Boolean = closedAt?.let { // allow 2 minute leeway for zap to propagate
pollNote?.createdAt()?.plus(it * (86400 + 120))!! > Date().time / 1000
} == true
val isVoteAmountAtomic = valueMaximum != null && valueMinimum != null && valueMinimum == valueMaximum
fun voteAmountPlaceHolderText(ctx: Context): String = if (valueMinimum == null && valueMaximum == null) {
ctx.getString(R.string.sats)
} else if (valueMinimum == null) {
"1—$valueMaximum " + ctx.getString(R.string.sats)
} else if (valueMaximum == null) {
">$valueMinimum " + ctx.getString(R.string.sats)
} else {
"$valueMinimum$valueMaximum " + ctx.getString(R.string.sats)
}
fun amount(textAmount: String) = if (textAmount.isEmpty()) { null } else {
try {
textAmount.toLong()
} catch (e: Exception) { null }
}
fun isValidAmount(amount: Long?): Boolean {
if (amount == null) {
return false
} else if (valueMinimum == null && valueMaximum == null) {
if (amount > 0) {
return true
}
} else if (valueMinimum == null) {
if (amount > 0 && amount <= valueMaximum!!) {
return true
}
} else if (valueMaximum == null) {
if (amount >= valueMinimum!!) {
return true
}
} else {
if ((valueMinimum!! <= amount) && (amount <= valueMaximum!!)) {
return true
}
}
return false
}
}