diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 8b0c9502d..5276a14cd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -4,21 +4,10 @@ import android.content.res.Resources import androidx.core.os.ConfigurationCompat import androidx.lifecycle.LiveData import com.vitorpamplona.amethyst.service.model.* -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.service.relays.Constants -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.service.relays.RelayPool -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.NonCancellable -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import com.vitorpamplona.amethyst.service.relays.* +import kotlinx.coroutines.* import nostr.postr.Persona -import java.util.Locale +import java.util.* import java.util.concurrent.atomic.AtomicBoolean val DefaultChannels = setOf( @@ -291,7 +280,7 @@ class Account( message: String, replyTo: List?, mentions: List?, - pollOptions: List>, + pollOptions: Map, valueMaximum: Int?, valueMinimum: Int?, consensusThreshold: Int?, @@ -535,7 +524,7 @@ class Account( isAcceptableDirect(note) && ( note.event !is RepostEvent || - (note.event is RepostEvent && note.replyTo?.firstOrNull { isAcceptableDirect(it) } != null) + (note.replyTo?.firstOrNull { isAcceptableDirect(it) } != null) ) // is not a reaction about a blocked post } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/model/PollNoteEvent.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/model/PollNoteEvent.kt index f6409aaac..91215db12 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/model/PollNoteEvent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/model/PollNoteEvent.kt @@ -46,7 +46,7 @@ class PollNoteEvent( addresses: List?, privateKey: ByteArray, createdAt: Long = Date().time / 1000, - pollOptions: List>, + pollOptions: Map, valueMaximum: Int?, valueMinimum: Int?, consensusThreshold: Int?, @@ -63,7 +63,7 @@ class PollNoteEvent( addresses?.forEach { tags.add(listOf("a", it.toTag())) } - tags.add(listOf(POLL_OPTIONS, pollOptions.toString())) + tags.add(listOf(POLL_OPTIONS, gson.toJson(pollOptions))) tags.add(listOf(VALUE_MAXIMUM, valueMaximum.toString())) tags.add(listOf(VALUE_MINIMUM, valueMinimum.toString())) tags.add(listOf(CONSENSUS_THRESHOLD, consensusThreshold.toString())) @@ -72,6 +72,10 @@ class PollNoteEvent( val sig = Utils.sign(id, privateKey) return PollNoteEvent(id.toHexKey(), pubKey, createdAt, tags, msg, sig.toHexKey()) } + + fun parseJsonPollOptions(s: String): Map { + return gson.fromJson>(s, MutableMap::class.java) + } } } @@ -84,10 +88,11 @@ class PollNoteEvent( "tags": [ ["e", <32-bytes hex of the id of the poll event>, ], ["p", <32-bytes hex of the key>, ], - ["poll_options", - "[[0, 'poll option 0 description string'], - [1, 'poll option 1 description string'], - [, 'poll option description string']]" + ["poll_options", "{ + \"0\": \"poll option 0 description string\", + \"1\": \"poll option 1 description string\", + \"n\": \"poll option description string\" + }" ], ["value_maximum", "maximum satoshi value for inclusion in tally"], ["value_minimum", "minimum satoshi value for inclusion in tally"], diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollView.kt index 22fa9d3ef..ddab2e4fa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollView.kt @@ -88,7 +88,7 @@ fun NewPollView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n onClose() }, isActive = pollViewModel.message.text.isNotBlank() && - pollViewModel.pollOptions.all { it.isNotEmpty() } && + pollViewModel.pollOptions.values.all { it.isNotEmpty() } && pollViewModel.isValidRecipients.value && pollViewModel.isValidvalueMaximum.value && pollViewModel.isValidvalueMinimum.value && @@ -116,11 +116,11 @@ fun NewPollView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n Text(stringResource(R.string.poll_heading_required)) PollRecipientsField(pollViewModel, account) PollPrimaryDescription(pollViewModel) - pollViewModel.pollOptions.forEachIndexed { index, element -> + pollViewModel.pollOptions.values.forEachIndexed { index, element -> PollOption(pollViewModel, index) } Button( - onClick = { pollViewModel.pollOptions.add("") }, + onClick = { pollViewModel.pollOptions.values.add("") }, border = BorderStroke(1.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.32f)), colors = ButtonDefaults.outlinedButtonColors( contentColor = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollViewModel.kt index 5b5b637e9..3119d65c4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollViewModel.kt @@ -1,15 +1,19 @@ package com.vitorpamplona.amethyst.ui.actions +import androidx.annotation.Keep import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.text.input.TextFieldValue +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import com.vitorpamplona.amethyst.model.* import com.vitorpamplona.amethyst.service.nip19.Nip19 class NewPollViewModel : NewPostViewModel() { var zapRecipients = mutableStateListOf() - var pollOptions = mutableStateListOf("", "") + var pollOptions = mutableStateMapOf(Pair(0, ""), Pair(1, "")) var valueMaximum: Int? = null var valueMinimum: Int? = null var consensusThreshold: Int? = null @@ -91,7 +95,7 @@ class NewPollViewModel : NewPostViewModel() { account?.sendPoll(newMessage, replyTos, mentions) }*/ - account?.sendPoll(newMessage, replyTos, mentions, getPollOptionsList(), valueMaximum, valueMinimum, consensusThreshold, closedAt) + account?.sendPoll(newMessage, replyTos, mentions, pollOptions, valueMaximum, valueMinimum, consensusThreshold, closedAt) clearPollStates() } @@ -126,18 +130,17 @@ class NewPollViewModel : NewPostViewModel() { mentions = null zapRecipients = mutableStateListOf() - pollOptions = mutableStateListOf("", "") + pollOptions = mutableStateMapOf(Pair(0, ""), Pair(1, "")) valueMaximum = null valueMinimum = null consensusThreshold = null closedAt = null } - - private fun getPollOptionsList(): List> { - val optionsList: MutableList> = mutableListOf() - pollOptions.forEachIndexed { i, s -> - optionsList.add(mapOf(Pair(i, s))) - } - return optionsList - } +} + +@Keep // Do not obfuscate! Variable names are needed for parsers +data class PollOptions(var poll_options: List) +fun parseJsonPollOption(json: String): PollOptions { + val typeToken = object : TypeToken() {}.type + return Gson().fromJson(json, typeToken) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollOption.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollOption.kt index 441c71142..0e275ecc7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollOption.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollOption.kt @@ -29,7 +29,7 @@ fun PollOption(pollViewModel: NewPollViewModel, optionIndex: Int) { OutlinedTextField( modifier = Modifier .weight(1F), - value = pollViewModel.pollOptions[optionIndex], + value = pollViewModel.pollOptions[optionIndex] ?: "", onValueChange = { pollViewModel.pollOptions[optionIndex] = it }, label = { Text( @@ -43,14 +43,14 @@ fun PollOption(pollViewModel: NewPollViewModel, optionIndex: Int) { color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) ) }, - colors = if (pollViewModel.pollOptions[optionIndex].isNotEmpty()) colorValid else colorInValid + colors = if (pollViewModel.pollOptions[optionIndex]?.isNotEmpty() == true) colorValid else colorInValid ) if (optionIndex > 1) { Button( modifier = Modifier .padding(start = 6.dp, top = 2.dp) .imePadding(), - onClick = { pollViewModel.pollOptions.removeAt(optionIndex) }, + onClick = { pollViewModel.pollOptions.remove(optionIndex) }, border = BorderStroke(1.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.32f)), colors = ButtonDefaults.outlinedButtonColors( contentColor = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)