Undisclosed poll implementation.
This commit is contained in:
parent
7f97e78ba3
commit
b0b92c062e
|
@ -22,7 +22,7 @@ import com.squareup.moshi.JsonClass
|
|||
@JsonClass(generateAdapter = true)
|
||||
data class PollCreationInfo(
|
||||
@Json(name = "question") val question: PollQuestion? = null,
|
||||
@Json(name = "kind") val kind: String? = "org.matrix.msc3381.poll.disclosed",
|
||||
@Json(name = "kind") val kind: PollType? = PollType.DISCLOSED,
|
||||
@Json(name = "max_selections") val maxSelections: Int = 1,
|
||||
@Json(name = "answers") val answers: List<PollAnswer>? = null
|
||||
)
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.message
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = false)
|
||||
enum class PollType {
|
||||
/**
|
||||
* Voters should see results as soon as they have voted.
|
||||
*/
|
||||
@Json(name = "org.matrix.msc3381.poll.disclosed")
|
||||
DISCLOSED,
|
||||
|
||||
/**
|
||||
* Results should be only revealed when the poll is ended.
|
||||
*/
|
||||
@Json(name = "org.matrix.msc3381.poll.undisclosed")
|
||||
UNDISCLOSED
|
||||
}
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.room.model.relation
|
|||
import androidx.lifecycle.LiveData
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
|
@ -66,11 +67,13 @@ interface RelationService {
|
|||
|
||||
/**
|
||||
* Edit a poll.
|
||||
* @param pollType indicates open or closed polls
|
||||
* @param targetEvent The poll event to edit
|
||||
* @param question The edited question
|
||||
* @param options The edited options
|
||||
*/
|
||||
fun editPoll(targetEvent: TimelineEvent,
|
||||
pollType: PollType,
|
||||
question: String,
|
||||
options: List<String>): Cancelable
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
|||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
|
||||
|
@ -91,11 +92,12 @@ interface SendService {
|
|||
|
||||
/**
|
||||
* Send a poll to the room.
|
||||
* @param pollType indicates open or closed polls
|
||||
* @param question the question
|
||||
* @param options list of options
|
||||
* @return a [Cancelable]
|
||||
*/
|
||||
fun sendPoll(question: String, options: List<String>): Cancelable
|
||||
fun sendPoll(pollType: PollType, question: String, options: List<String>): Cancelable
|
||||
|
||||
/**
|
||||
* Method to send a poll response.
|
||||
|
|
|
@ -24,6 +24,7 @@ import dagger.assisted.AssistedInject
|
|||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationService
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
|
@ -113,9 +114,10 @@ internal class DefaultRelationService @AssistedInject constructor(
|
|||
}
|
||||
|
||||
override fun editPoll(targetEvent: TimelineEvent,
|
||||
pollType: PollType,
|
||||
question: String,
|
||||
options: List<String>): Cancelable {
|
||||
return eventEditor.editPoll(targetEvent, question, options)
|
||||
return eventEditor.editPoll(targetEvent, pollType, question, options)
|
||||
}
|
||||
|
||||
override fun editTextMessage(targetEvent: TimelineEvent,
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.relation
|
|||
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
|
@ -59,17 +60,18 @@ internal class EventEditor @Inject constructor(private val eventSenderProcessor:
|
|||
}
|
||||
|
||||
fun editPoll(targetEvent: TimelineEvent,
|
||||
pollType: PollType,
|
||||
question: String,
|
||||
options: List<String>): Cancelable {
|
||||
val roomId = targetEvent.roomId
|
||||
if (targetEvent.root.sendState.hasFailed()) {
|
||||
val editedEvent = eventFactory.createPollEvent(roomId, question, options).copy(
|
||||
val editedEvent = eventFactory.createPollEvent(roomId, pollType, question, options).copy(
|
||||
eventId = targetEvent.eventId
|
||||
)
|
||||
return sendFailedEvent(targetEvent, editedEvent)
|
||||
} else if (targetEvent.root.sendState.isSent()) {
|
||||
val event = eventFactory
|
||||
.createPollReplaceEvent(roomId, targetEvent.eventId, question, options)
|
||||
.createPollReplaceEvent(roomId, pollType, targetEvent.eventId, question, options)
|
||||
return sendReplaceEvent(roomId, event)
|
||||
} else {
|
||||
Timber.w("Can't edit a sending event")
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
|
|||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||
import org.matrix.android.sdk.api.session.room.send.SendService
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
|
@ -103,8 +104,8 @@ internal class DefaultSendService @AssistedInject constructor(
|
|||
.let { sendEvent(it) }
|
||||
}
|
||||
|
||||
override fun sendPoll(question: String, options: List<String>): Cancelable {
|
||||
return localEchoEventFactory.createPollEvent(roomId, question, options)
|
||||
override fun sendPoll(pollType: PollType, question: String, options: List<String>): Cancelable {
|
||||
return localEchoEventFactory.createPollEvent(roomId, pollType, question, options)
|
||||
.also { createLocalEcho(it) }
|
||||
.let { sendEvent(it) }
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.matrix.android.sdk.api.session.room.model.message.PollAnswer
|
|||
import org.matrix.android.sdk.api.session.room.model.message.PollCreationInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollQuestion
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollResponse
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.ThumbnailInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.message.VideoInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
|
||||
|
@ -126,12 +127,14 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||
}
|
||||
|
||||
private fun createPollContent(question: String,
|
||||
options: List<String>): MessagePollContent {
|
||||
options: List<String>,
|
||||
pollType: PollType): MessagePollContent {
|
||||
return MessagePollContent(
|
||||
pollCreationInfo = PollCreationInfo(
|
||||
question = PollQuestion(
|
||||
question = question
|
||||
),
|
||||
kind = pollType,
|
||||
answers = options.map { option ->
|
||||
PollAnswer(
|
||||
id = UUID.randomUUID().toString(),
|
||||
|
@ -143,12 +146,13 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||
}
|
||||
|
||||
fun createPollReplaceEvent(roomId: String,
|
||||
pollType: PollType,
|
||||
targetEventId: String,
|
||||
question: String,
|
||||
options: List<String>): Event {
|
||||
val newContent = MessagePollContent(
|
||||
relatesTo = RelationDefaultContent(RelationType.REPLACE, targetEventId),
|
||||
newContent = createPollContent(question, options).toContent()
|
||||
newContent = createPollContent(question, options, pollType).toContent()
|
||||
)
|
||||
val localId = LocalEcho.createLocalEchoId()
|
||||
return Event(
|
||||
|
@ -186,9 +190,10 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||
}
|
||||
|
||||
fun createPollEvent(roomId: String,
|
||||
pollType: PollType,
|
||||
question: String,
|
||||
options: List<String>): Event {
|
||||
val content = createPollContent(question, options)
|
||||
val content = createPollContent(question, options, pollType)
|
||||
val localId = LocalEcho.createLocalEchoId()
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
|
|
|
@ -89,6 +89,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
|
|||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.getFileName
|
||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
||||
|
@ -186,11 +187,14 @@ class MessageItemFactory @Inject constructor(
|
|||
val didUserVoted = pollResponseSummary?.myVote?.isNotEmpty().orFalse()
|
||||
val winnerVoteCount = pollResponseSummary?.winnerVoteCount
|
||||
val isPollSent = informationData.sendState.isSent()
|
||||
val isPollUndisclosed = pollContent.pollCreationInfo?.kind == PollType.UNDISCLOSED
|
||||
|
||||
val totalVotesText = (pollResponseSummary?.totalVotes ?: 0).let {
|
||||
when {
|
||||
isEnded -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_after_ended, it, it)
|
||||
didUserVoted -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_before_ended_and_voted, it, it)
|
||||
else -> if (it == 0) {
|
||||
isEnded -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_after_ended, it, it)
|
||||
isPollUndisclosed -> ""
|
||||
didUserVoted -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_before_ended_and_voted, it, it)
|
||||
else -> if (it == 0) {
|
||||
stringProvider.getString(R.string.poll_no_votes_cast)
|
||||
} else {
|
||||
stringProvider.getQuantityString(R.plurals.poll_total_vote_count_before_ended_and_not_voted, it, it)
|
||||
|
@ -214,6 +218,9 @@ class MessageItemFactory @Inject constructor(
|
|||
// Poll is ended. Disable option, show votes and mark the winner.
|
||||
val isWinner = winnerVoteCount != 0 && voteCount == winnerVoteCount
|
||||
PollOptionViewState.PollEnded(optionId, optionAnswer, voteCount, votePercentage, isWinner)
|
||||
} else if (isPollUndisclosed) {
|
||||
// Poll is closed. Enable option, hide votes and mark the user's selection.
|
||||
PollOptionViewState.PollUndisclosed(optionId, optionAnswer, isMyVote)
|
||||
} else if (didUserVoted) {
|
||||
// User voted to the poll, but poll is not ended. Enable option, show votes and mark the user's selection.
|
||||
PollOptionViewState.PollVoted(optionId, optionAnswer, voteCount, votePercentage, isMyVote)
|
||||
|
|
|
@ -22,9 +22,9 @@ import androidx.core.view.children
|
|||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.charsequence.EpoxyCharSequence
|
||||
import im.vector.app.features.home.room.detail.RoomDetailAction
|
||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_base)
|
||||
abstract class PollItem : AbsMessageItem<PollItem.Holder>() {
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.appcompat.content.res.AppCompatResources
|
|||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.setAttributeTintedImageResource
|
||||
import im.vector.app.databinding.ItemPollOptionBinding
|
||||
|
||||
|
@ -43,11 +44,12 @@ class PollOptionView @JvmOverloads constructor(
|
|||
views.optionNameTextView.text = state.optionAnswer
|
||||
|
||||
when (state) {
|
||||
is PollOptionViewState.PollSending -> renderPollSending()
|
||||
is PollOptionViewState.PollEnded -> renderPollEnded(state)
|
||||
is PollOptionViewState.PollReady -> renderPollReady()
|
||||
is PollOptionViewState.PollVoted -> renderPollVoted(state)
|
||||
}
|
||||
is PollOptionViewState.PollSending -> renderPollSending()
|
||||
is PollOptionViewState.PollEnded -> renderPollEnded(state)
|
||||
is PollOptionViewState.PollReady -> renderPollReady()
|
||||
is PollOptionViewState.PollVoted -> renderPollVoted(state)
|
||||
is PollOptionViewState.PollUndisclosed -> renderPollUndisclosed(state)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun renderPollSending() {
|
||||
|
@ -78,6 +80,12 @@ class PollOptionView @JvmOverloads constructor(
|
|||
renderVoteSelection(state.isSelected)
|
||||
}
|
||||
|
||||
private fun renderPollUndisclosed(state: PollOptionViewState.PollUndisclosed) {
|
||||
views.optionCheckImageView.isVisible = true
|
||||
views.optionWinnerImageView.isVisible = false
|
||||
renderVoteSelection(state.isSelected)
|
||||
}
|
||||
|
||||
private fun showVotes(voteCount: Int, votePercentage: Double) {
|
||||
views.optionVoteCountTextView.apply {
|
||||
isVisible = true
|
||||
|
|
|
@ -51,4 +51,12 @@ sealed class PollOptionViewState(open val optionId: String,
|
|||
val votePercentage: Double,
|
||||
val isWinner: Boolean
|
||||
) : PollOptionViewState(optionId, optionAnswer)
|
||||
|
||||
/**
|
||||
* Represent a poll that is closed, votes will be hidden until the poll is ended.
|
||||
*/
|
||||
data class PollUndisclosed(override val optionId: String,
|
||||
override val optionAnswer: String,
|
||||
val isSelected: Boolean
|
||||
) : PollOptionViewState(optionId, optionAnswer)
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
package im.vector.app.features.poll.create
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
|
||||
sealed class CreatePollAction : VectorViewModelAction {
|
||||
data class OnQuestionChanged(val question: String) : CreatePollAction()
|
||||
data class OnOptionChanged(val index: Int, val option: String) : CreatePollAction()
|
||||
data class OnDeleteOption(val index: Int) : CreatePollAction()
|
||||
data class OnPollTypeChanged(val pollType: PollType) : CreatePollAction()
|
||||
object OnAddOption : CreatePollAction()
|
||||
object OnCreatePoll : CreatePollAction()
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import im.vector.app.core.ui.list.genericItem
|
|||
import im.vector.app.features.form.formEditTextItem
|
||||
import im.vector.app.features.form.formEditTextWithDeleteItem
|
||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import javax.inject.Inject
|
||||
|
||||
class CreatePollController @Inject constructor(
|
||||
|
@ -47,6 +48,26 @@ class CreatePollController @Inject constructor(
|
|||
val currentState = state ?: return
|
||||
val host = this
|
||||
|
||||
genericItem {
|
||||
id("poll_type_title")
|
||||
style(ItemStyle.BIG_TEXT)
|
||||
title(host.stringProvider.getString(R.string.poll_type_title).toEpoxyCharSequence())
|
||||
}
|
||||
|
||||
pollTypeSelectionItem {
|
||||
id("poll_type_selection")
|
||||
pollType(currentState.pollType)
|
||||
pollTypeChangedListener { _, id ->
|
||||
host.callback?.onPollTypeChanged(
|
||||
if (id == R.id.openPollTypeRadioButton) {
|
||||
PollType.DISCLOSED
|
||||
} else {
|
||||
PollType.UNDISCLOSED
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
genericItem {
|
||||
id("question_title")
|
||||
style(ItemStyle.BIG_TEXT)
|
||||
|
@ -110,5 +131,6 @@ class CreatePollController @Inject constructor(
|
|||
fun onOptionChanged(index: Int, option: String)
|
||||
fun onDeleteOption(index: Int)
|
||||
fun onAddOption()
|
||||
fun onPollTypeChanged(type: PollType)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.databinding.FragmentCreatePollBinding
|
||||
import im.vector.app.features.poll.create.CreatePollViewModel.Companion.MAX_OPTIONS_COUNT
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import javax.inject.Inject
|
||||
|
||||
@Parcelize
|
||||
|
@ -60,18 +61,18 @@ class CreatePollFragment @Inject constructor(
|
|||
|
||||
when (args.mode) {
|
||||
PollMode.CREATE -> {
|
||||
views.createPollTitle.text = getString(R.string.create_poll_title)
|
||||
views.createPollToolbar.title = getString(R.string.create_poll_title)
|
||||
views.createPollButton.text = getString(R.string.create_poll_title)
|
||||
}
|
||||
PollMode.EDIT -> {
|
||||
views.createPollTitle.text = getString(R.string.edit_poll_title)
|
||||
views.createPollToolbar.title = getString(R.string.edit_poll_title)
|
||||
views.createPollButton.text = getString(R.string.edit_poll_title)
|
||||
}
|
||||
}.exhaustive
|
||||
|
||||
views.createPollRecyclerView.configureWith(controller, disableItemAnimation = true)
|
||||
// workaround for https://github.com/vector-im/element-android/issues/4735
|
||||
views.createPollRecyclerView.setItemViewCacheSize(MAX_OPTIONS_COUNT + 4)
|
||||
views.createPollRecyclerView.setItemViewCacheSize(MAX_OPTIONS_COUNT + 6)
|
||||
controller.callback = this
|
||||
|
||||
views.createPollButton.debouncedClicks {
|
||||
|
@ -117,6 +118,10 @@ class CreatePollFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onPollTypeChanged(type: PollType) {
|
||||
viewModel.handle(CreatePollAction.OnPollTypeChanged(type))
|
||||
}
|
||||
|
||||
private fun handleSuccess() {
|
||||
requireActivity().finish()
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
|||
import im.vector.app.core.platform.VectorViewModel
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
|
||||
class CreatePollViewModel @AssistedInject constructor(
|
||||
|
@ -70,13 +71,15 @@ class CreatePollViewModel @AssistedInject constructor(
|
|||
val event = room.getTimeLineEvent(eventId) ?: return
|
||||
val content = event.getLastMessageContent() as? MessagePollContent ?: return
|
||||
|
||||
val pollType = content.pollCreationInfo?.kind ?: PollType.DISCLOSED
|
||||
val question = content.pollCreationInfo?.question?.question ?: ""
|
||||
val options = content.pollCreationInfo?.answers?.mapNotNull { it.answer } ?: List(MIN_OPTIONS_COUNT) { "" }
|
||||
|
||||
setState {
|
||||
copy(
|
||||
question = question,
|
||||
options = options
|
||||
options = options,
|
||||
pollType = pollType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +91,7 @@ class CreatePollViewModel @AssistedInject constructor(
|
|||
is CreatePollAction.OnDeleteOption -> handleOnDeleteOption(action.index)
|
||||
is CreatePollAction.OnOptionChanged -> handleOnOptionChanged(action.index, action.option)
|
||||
is CreatePollAction.OnQuestionChanged -> handleOnQuestionChanged(action.question)
|
||||
is CreatePollAction.OnPollTypeChanged -> handleOnPollTypeChanged(action.pollType)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,17 +106,17 @@ class CreatePollViewModel @AssistedInject constructor(
|
|||
}
|
||||
else -> {
|
||||
when (state.mode) {
|
||||
PollMode.CREATE -> room.sendPoll(state.question, nonEmptyOptions)
|
||||
PollMode.EDIT -> sendEditedPoll(state.editedEventId!!, state.question, nonEmptyOptions)
|
||||
PollMode.CREATE -> room.sendPoll(state.pollType, state.question, nonEmptyOptions)
|
||||
PollMode.EDIT -> sendEditedPoll(state.editedEventId!!, state.pollType, state.question, nonEmptyOptions)
|
||||
}
|
||||
_viewEvents.post(CreatePollViewEvents.Success)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendEditedPoll(editedEventId: String, question: String, options: List<String>) {
|
||||
private fun sendEditedPoll(editedEventId: String, pollType: PollType, question: String, options: List<String>) {
|
||||
val editedEvent = room.getTimeLineEvent(editedEventId) ?: return
|
||||
room.editPoll(editedEvent, question, options)
|
||||
room.editPoll(editedEvent, pollType, question, options)
|
||||
}
|
||||
|
||||
private fun handleOnAddOption() {
|
||||
|
@ -150,6 +154,14 @@ class CreatePollViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleOnPollTypeChanged(pollType: PollType) {
|
||||
setState {
|
||||
copy(
|
||||
pollType = pollType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun canCreatePoll(question: String, options: List<String>): Boolean {
|
||||
return question.isNotEmpty() &&
|
||||
options.filter { it.isNotEmpty() }.size >= MIN_OPTIONS_COUNT
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.poll.create
|
||||
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
|
||||
data class CreatePollViewState(
|
||||
val roomId: String,
|
||||
|
@ -25,7 +26,8 @@ data class CreatePollViewState(
|
|||
val question: String = "",
|
||||
val options: List<String> = List(CreatePollViewModel.MIN_OPTIONS_COUNT) { "" },
|
||||
val canCreatePoll: Boolean = false,
|
||||
val canAddMoreOptions: Boolean = true
|
||||
val canAddMoreOptions: Boolean = true,
|
||||
val pollType: PollType = PollType.DISCLOSED
|
||||
) : MavericksState {
|
||||
|
||||
constructor(args: CreatePollArgs) : this(
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.poll.create
|
||||
|
||||
import android.widget.RadioGroup
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import org.matrix.android.sdk.api.session.room.model.message.PollType
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_poll_type_selection)
|
||||
abstract class PollTypeSelectionItem : VectorEpoxyModel<PollTypeSelectionItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var pollType: PollType = PollType.DISCLOSED
|
||||
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||
var pollTypeChangedListener: RadioGroup.OnCheckedChangeListener? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.pollTypeRadioGroup.check(
|
||||
when (pollType) {
|
||||
PollType.DISCLOSED -> R.id.openPollTypeRadioButton
|
||||
PollType.UNDISCLOSED -> R.id.closedPollTypeRadioButton
|
||||
}
|
||||
)
|
||||
|
||||
holder.pollTypeRadioGroup.setOnCheckedChangeListener(pollTypeChangedListener)
|
||||
}
|
||||
|
||||
override fun unbind(holder: Holder) {
|
||||
super.unbind(holder)
|
||||
holder.pollTypeRadioGroup.setOnCheckedChangeListener(null)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val pollTypeRadioGroup by bind<RadioGroup>(R.id.pollTypeRadioGroup)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/pollTypeRadioGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/layout_vertical_margin">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/openPollTypeRadioButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="0dp"
|
||||
android:text="@string/open_poll_option_title" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.Vector.Caption"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:text="@string/open_poll_option_description" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/closedPollTypeRadioButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:minHeight="0dp"
|
||||
android:text="@string/closed_poll_option_title" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.Vector.Caption"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:text="@string/closed_poll_option_description" />
|
||||
|
||||
</RadioGroup>
|
|
@ -3708,12 +3708,17 @@
|
|||
<string name="end_poll_confirmation_description">This will stop people from being able to vote and will display the final results of the poll.</string>
|
||||
<string name="end_poll_confirmation_approve_button">End poll</string>
|
||||
<string name="labs_enable_polls">Enable Polls</string>
|
||||
<string name="poll_response_room_list_preview">Vote casted</string>
|
||||
<string name="poll_response_room_list_preview">Vote cast</string>
|
||||
<string name="poll_end_room_list_preview">Poll ended</string>
|
||||
<string name="delete_poll_dialog_title">Remove poll</string>
|
||||
<string name="delete_poll_dialog_content">Are you sure you want to remove this poll? You won\'t be able to recover it once removed.</string>
|
||||
<string name="edit_poll_title">Edit poll</string>
|
||||
<string name="edit_poll_button">EDIT POLL</string>
|
||||
<string name="poll_type_title">Poll type</string>
|
||||
<string name="open_poll_option_title">Open poll</string>
|
||||
<string name="open_poll_option_description">Voters see results as soon as they have voted</string>
|
||||
<string name="closed_poll_option_title">Closed poll</string>
|
||||
<string name="closed_poll_option_description">Results are only revealed when you end the poll</string>
|
||||
|
||||
<string name="tooltip_attachment_photo">Open camera</string>
|
||||
<string name="tooltip_attachment_gallery">Send images and videos</string>
|
||||
|
|
Loading…
Reference in New Issue