Activates min/max values for polls
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.actions
|
package com.vitorpamplona.amethyst.ui.actions
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.OutlinedTextField
|
import androidx.compose.material.OutlinedTextField
|
||||||
@@ -11,8 +13,6 @@ import androidx.compose.material.Text
|
|||||||
import androidx.compose.material.TextFieldDefaults
|
import androidx.compose.material.TextFieldDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -21,51 +21,11 @@ import androidx.compose.ui.text.input.KeyboardType
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) {
|
fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) {
|
||||||
var textMax by rememberSaveable { mutableStateOf("") }
|
|
||||||
var textMin by rememberSaveable { mutableStateOf("") }
|
|
||||||
|
|
||||||
// check for zapMax amounts < 1
|
|
||||||
pollViewModel.isValidvalueMaximum.value = true
|
|
||||||
if (textMax.isNotEmpty()) {
|
|
||||||
try {
|
|
||||||
val int = textMax.toInt()
|
|
||||||
if (int < 1) {
|
|
||||||
pollViewModel.isValidvalueMaximum.value = false
|
|
||||||
} else { pollViewModel.valueMaximum = int }
|
|
||||||
} catch (e: Exception) { pollViewModel.isValidvalueMaximum.value = false }
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for minZap amounts < 1
|
|
||||||
pollViewModel.isValidvalueMinimum.value = true
|
|
||||||
if (textMin.isNotEmpty()) {
|
|
||||||
try {
|
|
||||||
val int = textMin.toInt()
|
|
||||||
if (int < 1) {
|
|
||||||
pollViewModel.isValidvalueMinimum.value = false
|
|
||||||
} else { pollViewModel.valueMinimum = int }
|
|
||||||
} catch (e: Exception) { pollViewModel.isValidvalueMinimum.value = false }
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for zapMin > zapMax
|
|
||||||
if (textMin.isNotEmpty() && textMax.isNotEmpty()) {
|
|
||||||
try {
|
|
||||||
val intMin = textMin.toInt()
|
|
||||||
val intMax = textMax.toInt()
|
|
||||||
|
|
||||||
if (intMin > intMax) {
|
|
||||||
pollViewModel.isValidvalueMinimum.value = false
|
|
||||||
pollViewModel.isValidvalueMaximum.value = false
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
pollViewModel.isValidvalueMinimum.value = false
|
|
||||||
pollViewModel.isValidvalueMaximum.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val colorInValid = TextFieldDefaults.outlinedTextFieldColors(
|
val colorInValid = TextFieldDefaults.outlinedTextFieldColors(
|
||||||
focusedBorderColor = MaterialTheme.colors.error,
|
focusedBorderColor = MaterialTheme.colors.error,
|
||||||
unfocusedBorderColor = Color.Red
|
unfocusedBorderColor = Color.Red
|
||||||
@@ -80,10 +40,10 @@ fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) {
|
|||||||
horizontalArrangement = Arrangement.Center
|
horizontalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = textMin,
|
value = pollViewModel.valueMinimum?.toString() ?: "",
|
||||||
onValueChange = { textMin = it },
|
onValueChange = { pollViewModel.updateMinZapAmountForPoll(it) },
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
modifier = Modifier.width(150.dp),
|
modifier = Modifier.weight(1f),
|
||||||
colors = if (pollViewModel.isValidvalueMinimum.value) colorValid else colorInValid,
|
colors = if (pollViewModel.isValidvalueMinimum.value) colorValid else colorInValid,
|
||||||
label = {
|
label = {
|
||||||
Text(
|
Text(
|
||||||
@@ -98,11 +58,14 @@ fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = DoubleHorzSpacer)
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = textMax,
|
value = pollViewModel.valueMaximum?.toString() ?: "",
|
||||||
onValueChange = { textMax = it },
|
onValueChange = { pollViewModel.updateMaxZapAmountForPoll(it) },
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
modifier = Modifier.width(150.dp),
|
modifier = Modifier.weight(1f),
|
||||||
colors = if (pollViewModel.isValidvalueMaximum.value) colorValid else colorInValid,
|
colors = if (pollViewModel.isValidvalueMaximum.value) colorValid else colorInValid,
|
||||||
label = {
|
label = {
|
||||||
Text(
|
Text(
|
||||||
@@ -118,10 +81,25 @@ fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.poll_zap_value_min_max_explainer),
|
||||||
|
color = MaterialTheme.colors.placeholderText,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun NewPollVoteValueRangePreview() {
|
fun NewPollVoteValueRangePreview() {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
NewPollVoteValueRange(NewPostViewModel())
|
NewPollVoteValueRange(NewPostViewModel())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -518,6 +518,8 @@ private fun PollField(postViewModel: NewPostViewModel) {
|
|||||||
NewPollOption(postViewModel, index)
|
NewPollOption(postViewModel, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NewPollVoteValueRange(postViewModel)
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
postViewModel.pollOptions[postViewModel.pollOptions.size] =
|
postViewModel.pollOptions[postViewModel.pollOptions.size] =
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
var wantsPoll by mutableStateOf(false)
|
var wantsPoll by mutableStateOf(false)
|
||||||
var zapRecipients = mutableStateListOf<HexKey>()
|
var zapRecipients = mutableStateListOf<HexKey>()
|
||||||
var pollOptions = newStateMapPollOptions()
|
var pollOptions = newStateMapPollOptions()
|
||||||
var valueMaximum: Int? = null
|
var valueMaximum by mutableStateOf<Int?>(null)
|
||||||
var valueMinimum: Int? = null
|
var valueMinimum by mutableStateOf<Int?>(null)
|
||||||
var consensusThreshold: Int? = null
|
var consensusThreshold: Int? = null
|
||||||
var closedAt: Int? = null
|
var closedAt: Int? = null
|
||||||
|
|
||||||
@@ -494,7 +494,7 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
return message.text.isNotBlank() && !isUploadingImage && !wantsInvoice &&
|
return message.text.isNotBlank() && !isUploadingImage && !wantsInvoice &&
|
||||||
(!wantsZapraiser || zapRaiserAmount != null) &&
|
(!wantsZapraiser || zapRaiserAmount != null) &&
|
||||||
(!wantsDirectMessage || !toUsers.text.isNullOrBlank()) &&
|
(!wantsDirectMessage || !toUsers.text.isNullOrBlank()) &&
|
||||||
(!wantsPoll || pollOptions.values.all { it.isNotEmpty() }) &&
|
(!wantsPoll || (pollOptions.values.all { it.isNotEmpty() } && isValidvalueMinimum.value && isValidvalueMaximum.value)) &&
|
||||||
contentToAddUrl == null
|
contentToAddUrl == null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,6 +612,50 @@ open class NewPostViewModel() : ViewModel() {
|
|||||||
nip24 = !nip24
|
nip24 = !nip24
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateMinZapAmountForPoll(textMin: String) {
|
||||||
|
if (textMin.isNotEmpty()) {
|
||||||
|
try {
|
||||||
|
val int = textMin.toInt()
|
||||||
|
if (int < 1) {
|
||||||
|
valueMinimum = null
|
||||||
|
} else {
|
||||||
|
valueMinimum = int
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {}
|
||||||
|
} else {
|
||||||
|
valueMinimum = null
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMinMax()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateMaxZapAmountForPoll(textMax: String) {
|
||||||
|
if (textMax.isNotEmpty()) {
|
||||||
|
try {
|
||||||
|
val int = textMax.toInt()
|
||||||
|
if (int < 1) {
|
||||||
|
valueMaximum = null
|
||||||
|
} else {
|
||||||
|
valueMaximum = int
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {}
|
||||||
|
} else {
|
||||||
|
valueMaximum = null
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMinMax()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkMinMax() {
|
||||||
|
if ((valueMinimum ?: 0) > (valueMaximum ?: Int.MAX_VALUE)) {
|
||||||
|
isValidvalueMinimum.value = false
|
||||||
|
isValidvalueMaximum.value = false
|
||||||
|
} else {
|
||||||
|
isValidvalueMinimum.value = true
|
||||||
|
isValidvalueMaximum.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class GeohashPrecision(val digits: Int) {
|
enum class GeohashPrecision(val digits: Int) {
|
||||||
|
|||||||
@@ -551,4 +551,6 @@
|
|||||||
<string name="rules">Rules</string>
|
<string name="rules">Rules</string>
|
||||||
|
|
||||||
<string name="status_update">Update your status</string>
|
<string name="status_update">Update your status</string>
|
||||||
|
|
||||||
|
<string name="poll_zap_value_min_max_explainer">Votes are weighted by the zap amount. You can set a minimum amount to avoid spammers and a maximum amount to avoid a large zappers taking over the poll. Use the same amount in both fields to make sure every vote is valued the same amount. Leave it empty to accept any amount.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user