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 9645fc180..8b0c9502d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -3,20 +3,7 @@ package com.vitorpamplona.amethyst.model import android.content.res.Resources import androidx.core.os.ConfigurationCompat import androidx.lifecycle.LiveData -import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent -import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent -import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent -import com.vitorpamplona.amethyst.service.model.Contact -import com.vitorpamplona.amethyst.service.model.ContactListEvent -import com.vitorpamplona.amethyst.service.model.DeletionEvent -import com.vitorpamplona.amethyst.service.model.IdentityClaim -import com.vitorpamplona.amethyst.service.model.LnZapRequestEvent -import com.vitorpamplona.amethyst.service.model.MetadataEvent -import com.vitorpamplona.amethyst.service.model.PrivateDmEvent -import com.vitorpamplona.amethyst.service.model.ReactionEvent -import com.vitorpamplona.amethyst.service.model.ReportEvent -import com.vitorpamplona.amethyst.service.model.RepostEvent -import com.vitorpamplona.amethyst.service.model.TextNoteEvent +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 @@ -300,6 +287,39 @@ class Account( LocalCache.consume(signedEvent) } + fun sendPoll( + message: String, + replyTo: List?, + mentions: List?, + pollOptions: List>, + valueMaximum: Int?, + valueMinimum: Int?, + consensusThreshold: Int?, + closedAt: Int? + ) { + if (!isWriteable()) return + + val repliesToHex = replyTo?.map { it.idHex } + val mentionsHex = mentions?.map { it.pubkeyHex } + val addresses = replyTo?.mapNotNull { it.address() } + + val signedEvent = PollNoteEvent.create( + msg = message, + replyTos = repliesToHex, + mentions = mentionsHex, + addresses = addresses, + privateKey = loggedIn.privKey!!, + pollOptions = pollOptions, + valueMaximum = valueMaximum, + valueMinimum = valueMinimum, + consensusThreshold = consensusThreshold, + closedAt = closedAt + ) + println("PollNoteEvent: %s".format(signedEvent.toJson())) + // Client.send(signedEvent) + // LocalCache.consume(signedEvent) + } + fun sendChannelMessage(message: String, toChannel: String, replyingTo: Note? = null, mentions: List?) { if (!isWriteable()) return 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 6cb15d4a9..f6409aaac 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 @@ -16,7 +16,7 @@ class PollNoteEvent( pubKey: HexKey, createdAt: Long, tags: List>, - // ots: , TODO implement OTS: https://github.com/opentimestamps/java-opentimestamps + // ots: String?, TODO implement OTS: https://github.com/opentimestamps/java-opentimestamps content: String, sig: HexKey ) : Event(id, pubKey, createdAt, kind, tags, content, sig) { @@ -63,9 +63,7 @@ class PollNoteEvent( addresses?.forEach { tags.add(listOf("a", it.toTag())) } - pollOptions.forEach { - tags.add(listOf(POLL_OPTIONS, it.toString())) - } + tags.add(listOf(POLL_OPTIONS, pollOptions.toString())) tags.add(listOf(VALUE_MAXIMUM, valueMaximum.toString())) tags.add(listOf(VALUE_MINIMUM, valueMinimum.toString())) tags.add(listOf(CONSENSUS_THRESHOLD, consensusThreshold.toString())) 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 ee54ae23b..c3c768b31 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 @@ -84,7 +84,7 @@ fun NewPollView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n PollButton( onPost = { - pollViewModel.sendPost() + pollViewModel.sendPoll() onClose() }, isActive = pollViewModel.message.text.isNotBlank() && 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 e54c2107f..2259cc83e 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 @@ -2,19 +2,17 @@ package com.vitorpamplona.amethyst.ui.actions import androidx.compose.runtime.mutableStateListOf import androidx.compose.ui.text.input.TextFieldValue -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.HexKey -import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.model.* +import com.vitorpamplona.amethyst.service.nip19.Nip19 class NewPollViewModel : NewPostViewModel() { var zapRecipients = mutableStateListOf() var pollOptions = mutableStateListOf("", "") - var zapMax: Int? = null - var zapMin: Int? = null - var consensus: Int? = null - var closedAfter: Int? = null + var valueMaximum: Int? = null + var valueMinimum: Int? = null + var consensusThreshold: Int? = null + var closedAt: Int? = null override fun load(account: Account, replyingTo: Note?, quote: Note?) { super.load(account, replyingTo, quote) @@ -36,16 +34,65 @@ class NewPollViewModel : NewPostViewModel() { return super.tagIndex(note) } - override fun sendPost() { - super.sendPost() + fun sendPoll() { + // adds all references to mentions and reply tos + message.text.split('\n').forEach { paragraph: String -> + paragraph.split(' ').forEach { word: String -> + val results = parseDirtyWordForKey(word) - clearStates() + if (results?.key?.type == Nip19.Type.USER) { + addUserToMentions(LocalCache.getOrCreateUser(results.key.hex)) + } else if (results?.key?.type == Nip19.Type.NOTE) { + addNoteToReplyTos(LocalCache.getOrCreateNote(results.key.hex)) + } else if (results?.key?.type == Nip19.Type.ADDRESS) { + val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex) + if (note != null) { + addNoteToReplyTos(note) + } + } + } + } + + // Tags the text in the correct order. + val newMessage = message.text.split('\n').map { paragraph: String -> + paragraph.split(' ').map { word: String -> + val results = parseDirtyWordForKey(word) + if (results?.key?.type == Nip19.Type.USER) { + val user = LocalCache.getOrCreateUser(results.key.hex) + + "#[${tagIndex(user)}]${results.restOfWord}" + } else if (results?.key?.type == Nip19.Type.NOTE) { + val note = LocalCache.getOrCreateNote(results.key.hex) + + "#[${tagIndex(note)}]${results.restOfWord}" + } else if (results?.key?.type == Nip19.Type.ADDRESS) { + val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex) + if (note != null) { + "#[${tagIndex(note)}]${results.restOfWord}" + } else { + word + } + } else { + word + } + }.joinToString(" ") + }.joinToString("\n") + + /* if (originalNote?.channel() != null) { + account?.sendChannelMessage(newMessage, originalNote!!.channel()!!.idHex, originalNote!!, mentions) + } else { + account?.sendPoll(newMessage, replyTos, mentions) + }*/ + + account?.sendPoll(newMessage, replyTos, mentions, getPollOptionsList(), valueMaximum, valueMinimum, consensusThreshold, closedAt) + + clearPollStates() } override fun cancel() { super.cancel() - clearStates() + clearPollStates() } override fun findUrlInMessage(): String? { @@ -64,13 +111,26 @@ class NewPollViewModel : NewPostViewModel() { super.autocompleteWithUser(item) } - private fun clearStates() { - // clear states + // clear all states + private fun clearPollStates() { + message = TextFieldValue("") + urlPreview = null + isUploadingImage = false + mentions = null + zapRecipients = mutableStateListOf() pollOptions = mutableStateListOf("", "") - zapMax = null - zapMin = null - consensus = null - closedAfter = null + 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 } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 98feff723..d80a5b07b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -71,7 +71,7 @@ open class NewPostViewModel : ViewModel() { return (if (originalNote?.channel() != null) 1 else 0) + (replyTos?.indexOf(note) ?: 0) } - open fun sendPost() { + fun sendPost() { // adds all references to mentions and reply tos message.text.split('\n').forEach { paragraph: String -> paragraph.split(' ').forEach { word: String -> diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollClosing.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollClosing.kt index c3dd9251c..9d4e45f3f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollClosing.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollClosing.kt @@ -33,7 +33,7 @@ fun PollClosing(pollViewModel: NewPollViewModel) { val int = text.toInt() if (int < 0) { isInputValid = false - } else { pollViewModel.closedAfter = int } + } else { pollViewModel.closedAt = int } } catch (e: Exception) { isInputValid = false } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollConsensusThreshold.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollConsensusThreshold.kt index 2920d00b9..f60a11e77 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollConsensusThreshold.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollConsensusThreshold.kt @@ -33,7 +33,7 @@ fun PollConsensusThreshold(pollViewModel: NewPollViewModel) { val int = text.toInt() if (int < 0 || int > 100) { isInputValid = false - } else { pollViewModel.consensus = int } + } else { pollViewModel.consensusThreshold = int } } catch (e: Exception) { isInputValid = false } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollVoteValueRange.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollVoteValueRange.kt index 9e9160256..fa6f93c62 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollVoteValueRange.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/PollVoteValueRange.kt @@ -33,9 +33,9 @@ fun PollVoteValueRange(pollViewModel: NewPollViewModel) { if (textMax.isNotEmpty()) { try { val int = textMax.toInt() - if ( int < 1) + if (int < 1) { isMaxValid = false - else pollViewModel.zapMax = int + } else { pollViewModel.valueMaximum = int } } catch (e: Exception) { isMaxValid = false } } @@ -44,9 +44,9 @@ fun PollVoteValueRange(pollViewModel: NewPollViewModel) { if (textMin.isNotEmpty()) { try { val int = textMin.toInt() - if ( int < 1) + if (int < 1) { isMinValid = false - else pollViewModel.zapMin = int + } else { pollViewModel.valueMinimum = int } } catch (e: Exception) { isMinValid = false } } @@ -56,7 +56,7 @@ fun PollVoteValueRange(pollViewModel: NewPollViewModel) { val intMin = textMin.toInt() val intMax = textMax.toInt() - if ( intMin > intMax) { + if (intMin > intMax) { isMinValid = false isMaxValid = false } @@ -68,7 +68,8 @@ fun PollVoteValueRange(pollViewModel: NewPollViewModel) { val colorInValid = TextFieldDefaults.outlinedTextFieldColors( focusedBorderColor = MaterialTheme.colors.error, - unfocusedBorderColor = Color.Red) + unfocusedBorderColor = Color.Red + ) val colorValid = TextFieldDefaults.outlinedTextFieldColors( focusedBorderColor = MaterialTheme.colors.primary, unfocusedBorderColor = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)