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] }
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 }
.getOrNull(1)?.getOrNull(1)?.toInt()
fun getTagInt(property: String): Int? {
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 }
.getOrNull(1)?.getOrNull(1)?.toInt()
fun closedAt(): Int? = tags.filter { it.firstOrNull() == CLOSED_AT }
.getOrNull(1)?.getOrNull(1)?.toInt()
return if (s.isNullOrBlank() || s == "null") {
null
} else {
s.toInt()
}
}
companion object {
const val kind = 6969
@@ -26,10 +26,10 @@ 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
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
@@ -44,10 +44,10 @@ fun PollNote(
accountViewModel: AccountViewModel,
navController: NavController
) {
val pollEvent = note.event as PollNoteEvent
val consensusThreshold = pollEvent.consensusThreshold()
val pollViewModel: PollNoteViewModel = viewModel()
pollViewModel.load(note)
pollEvent.pollOptions().forEach { poll_op ->
pollViewModel.pollEvent?.pollOptions()?.forEach { poll_op ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
@@ -56,16 +56,16 @@ fun PollNote(
poll_op.value,
canPreview,
modifier = Modifier
.weight(1f)
.width(250.dp)
.border(BorderStroke(1.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.32f)))
.padding(4.dp),
pollEvent.tags(),
pollViewModel.pollEvent?.tags(),
backgroundColor,
accountViewModel,
navController
)
ZapVote(note, accountViewModel, poll_op.key)
ZapVote(note, accountViewModel, pollViewModel, poll_op.key)
}
}
}
@@ -75,6 +75,7 @@ fun PollNote(
fun ZapVote(
baseNote: Note,
accountViewModel: AccountViewModel,
pollViewModel: PollNoteViewModel,
pollOption: Int,
modifier: Modifier = Modifier
) {
@@ -89,15 +90,6 @@ fun ZapVote(
val context = LocalContext.current
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(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@@ -117,7 +109,7 @@ fun ZapVote(
)
.show()
}
} else if (isPollClosed) {
} else if (pollViewModel.isPollClosed) {
scope.launch {
Toast
.makeText(
@@ -127,10 +119,10 @@ fun ZapVote(
)
.show()
}
} else if (isVoteAmountAtomic) {
} else if (pollViewModel.isVoteAmountAtomic) {
accountViewModel.zap(
baseNote,
valueMaximum!!.toLong() * 1000,
pollViewModel.valueMaximum!!.toLong() * 1000,
pollOption,
"",
context
@@ -152,9 +144,8 @@ fun ZapVote(
ZapVoteAmountChoicePopup(
baseNote,
accountViewModel,
pollViewModel,
pollOption,
valueMinimum,
valueMaximum,
onDismiss = {
wantsToZap = false
},
@@ -183,12 +174,14 @@ fun ZapVote(
}
}
Text(
showAmount(zappedNote?.zappedPollOptionAmount(pollOption)),
fontSize = 14.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
modifier = modifier
)
if (zappedNote?.isZappedBy(account.userProfile()) == true) {
Text(
showAmount(zappedNote.zappedPollOptionAmount(pollOption)),
fontSize = 14.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
modifier = modifier
)
}
}
@OptIn(ExperimentalFoundationApi::class)
@@ -196,9 +189,8 @@ fun ZapVote(
fun ZapVoteAmountChoicePopup(
baseNote: Note,
accountViewModel: AccountViewModel,
pollViewModel: PollNoteViewModel,
pollOption: Int,
valueMinimum: Int?,
valueMaximum: Int?,
onDismiss: () -> Unit,
onError: (text: String) -> Unit
) {
@@ -206,43 +198,6 @@ fun ZapVoteAmountChoicePopup(
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(
focusedBorderColor = MaterialTheme.colors.error,
unfocusedBorderColor = Color.Red
@@ -266,12 +221,14 @@ fun ZapVoteAmountChoicePopup(
modifier = Modifier
.padding(10.dp)
) {
val amount = pollViewModel.amount(textAmount)
OutlinedTextField(
value = textAmount,
onValueChange = { textAmount = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
modifier = Modifier.width(150.dp),
colors = if (isValidAmount) colorValid else colorInValid,
colors = if (pollViewModel.isValidAmount(amount)) colorValid else colorInValid,
label = {
Text(
text = stringResource(R.string.poll_zap_amount),
@@ -280,7 +237,7 @@ fun ZapVoteAmountChoicePopup(
},
placeholder = {
Text(
text = placeHolderText,
text = pollViewModel.voteAmountPlaceHolderText(context),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
}
@@ -288,7 +245,7 @@ fun ZapVoteAmountChoicePopup(
Button(
modifier = Modifier.padding(horizontal = 3.dp),
enabled = isValidAmount,
enabled = pollViewModel.isValidAmount(amount),
onClick = {
if (amount != null) {
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
}
}