update poll UI for moderators etc

- allow to end poll for moderators

- allow to see voters amount for voting screen for moderators and creators of the poll

- replace UserEntity with User

- show numVoters instead of votes

- minor refactoring

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2022-07-14 14:45:12 +02:00 committed by Andy Scherzinger (Rebase PR Action)
parent c848659fda
commit 40f20c56d6
11 changed files with 137 additions and 51 deletions

View File

@ -121,12 +121,14 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : MessageH
if (pollId != null && pollName != null) {
binding.messagePollTitle.text = pollName
val roomToken = (payload as? MessagePayload)!!.roomToken
val roomToken = (payload as? MessagePayload)!!.currentConversation.token!!
val isOwnerOrModerator = (payload as? MessagePayload)!!.currentConversation.isParticipantOwnerOrModerator
binding.bubble.setOnClickListener {
val pollVoteDialog = PollMainDialogFragment.newInstance(
message.activeUser!!,
roomToken,
isOwnerOrModerator,
pollId,
pollName
)

View File

@ -1,8 +1,9 @@
package com.nextcloud.talk.adapters.messages
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet
data class MessagePayload(
val roomToken: String,
var currentConversation: Conversation,
val profileBottomSheet: ProfileBottomSheet
)

View File

@ -137,12 +137,14 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) : Messag
if (pollId != null && pollName != null) {
binding.messagePollTitle.text = pollName
val roomToken = (payload as? MessagePayload)!!.roomToken
val roomToken = (payload as? MessagePayload)!!.currentConversation.token!!
val isOwnerOrModerator = (payload as? MessagePayload)!!.currentConversation.isParticipantOwnerOrModerator
binding.bubble.setOnClickListener {
val pollVoteDialog = PollMainDialogFragment.newInstance(
message.activeUser!!,
roomToken,
isOwnerOrModerator,
pollId,
pollName
)

View File

@ -487,7 +487,7 @@ class ChatController(args: Bundle) :
val messageHolders = MessageHolders()
val profileBottomSheet = ProfileBottomSheet(ncApi!!, conversationUser!!, router)
val payload = MessagePayload(roomToken!!, profileBottomSheet)
val payload = MessagePayload(currentConversation!!, profileBottomSheet)
messageHolders.setIncomingTextConfig(
MagicIncomingTextMessageViewHolder::class.java,

View File

@ -26,14 +26,14 @@ import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.interfaces.DraweeController
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.PollResultVoterItemBinding
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.polls.model.PollDetails
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils
class PollResultVoterViewHolder(
private val user: UserEntity,
private val user: User,
override val binding: PollResultVoterItemBinding
) : PollResultViewHolder(binding) {
@ -60,7 +60,7 @@ class PollResultVoterViewHolder(
displayName,
false
),
null
user
)
)
.build()
@ -74,7 +74,7 @@ class PollResultVoterViewHolder(
pollDetail.actorId,
false
),
null
user
)
)
.build()

View File

@ -23,12 +23,12 @@ package com.nextcloud.talk.polls.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.PollResultHeaderItemBinding
import com.nextcloud.talk.databinding.PollResultVoterItemBinding
import com.nextcloud.talk.models.database.UserEntity
class PollResultsAdapter(
private val user: UserEntity,
private val user: User,
private val clickListener: PollResultItemClickListener,
) : RecyclerView.Adapter<PollResultViewHolder>() {
internal var list: MutableList<PollResultItem> = ArrayList()

View File

@ -32,17 +32,17 @@ import androidx.lifecycle.ViewModelProvider
import autodagger.AutoInjector
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.DialogPollMainBinding
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.polls.model.Poll
import com.nextcloud.talk.polls.viewmodels.PollMainViewModel
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class PollMainDialogFragment : DialogFragment() {
lateinit var user: UserEntity
lateinit var user: User
lateinit var roomToken: String
private var isOwnerOrModerator: Boolean = false
lateinit var pollId: String
lateinit var pollTitle: String
@ -60,6 +60,7 @@ class PollMainDialogFragment : DialogFragment() {
user = arguments?.getParcelable(KEY_USER_ENTITY)!!
roomToken = arguments?.getString(KEY_ROOM_TOKEN)!!
isOwnerOrModerator = arguments?.getBoolean(KEY_OWNER_OR_MODERATOR)!!
pollId = arguments?.getString(KEY_POLL_ID)!!
pollTitle = arguments?.getString(KEY_POLL_TITLE)!!
}
@ -83,19 +84,28 @@ class PollMainDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.setIsOwnerOrModerator(isOwnerOrModerator)
viewModel.viewState.observe(viewLifecycleOwner) { state ->
when (state) {
PollMainViewModel.InitialState -> {}
is PollMainViewModel.PollVoteHiddenState -> {
binding.pollDetailsText.visibility = View.VISIBLE
binding.pollDetailsText.text = context?.resources?.getString(R.string.polls_private_voted)
binding.pollVotedHidden.visibility = View.VISIBLE
initVotersAmount(state.showVotersAmount, state.poll.numVoters, false)
showVoteScreen()
}
is PollMainViewModel.PollVoteState -> {
binding.pollDetailsText.visibility = View.GONE
binding.pollVotedHidden.visibility = View.GONE
initVotersAmount(state.showVotersAmount, state.poll.numVoters, false)
showVoteScreen()
}
is PollMainViewModel.PollResultState -> showResultsScreen(state.poll)
is PollMainViewModel.PollResultState -> {
binding.pollVotedHidden.visibility = View.GONE
initVotersAmount(state.showVotersAmount, state.poll.numVoters, true)
showResultsScreen()
}
else -> {}
}
}
@ -103,7 +113,6 @@ class PollMainDialogFragment : DialogFragment() {
}
private fun showVoteScreen() {
val contentFragment = PollVoteFragment.newInstance(
roomToken,
pollId
@ -114,9 +123,7 @@ class PollMainDialogFragment : DialogFragment() {
transaction.commit()
}
private fun showResultsScreen(poll: Poll) {
initVotesAmount(poll.totalVotes)
private fun showResultsScreen() {
val contentFragment = PollResultsFragment.newInstance(
user
)
@ -126,12 +133,24 @@ class PollMainDialogFragment : DialogFragment() {
transaction.commit()
}
private fun initVotesAmount(totalVotes: Int) {
binding.pollDetailsText.visibility = View.VISIBLE
binding.pollDetailsText.text = String.format(
resources.getString(R.string.polls_amount_voters),
totalVotes
)
private fun initVotersAmount(showVotersAmount: Boolean, numVoters: Int, showResultSubtitle: Boolean) {
if (showVotersAmount) {
binding.pollVotesAmount.visibility = View.VISIBLE
binding.pollVotesAmount.text = String.format(
resources.getString(R.string.polls_amount_voters),
numVoters
)
} else {
binding.pollVotesAmount.visibility = View.GONE
}
if (showResultSubtitle) {
binding.pollResultsSubtitle.visibility = View.VISIBLE
binding.pollResultsSubtitleSeperator.visibility = View.VISIBLE
} else {
binding.pollResultsSubtitle.visibility = View.GONE
binding.pollResultsSubtitleSeperator.visibility = View.GONE
}
}
/**
@ -140,19 +159,22 @@ class PollMainDialogFragment : DialogFragment() {
companion object {
private const val KEY_USER_ENTITY = "keyUserEntity"
private const val KEY_ROOM_TOKEN = "keyRoomToken"
private const val KEY_OWNER_OR_MODERATOR = "keyIsOwnerOrModerator"
private const val KEY_POLL_ID = "keyPollId"
private const val KEY_POLL_TITLE = "keyPollTitle"
@JvmStatic
fun newInstance(
user: UserEntity,
user: User,
roomTokenParam: String,
isOwnerOrModerator: Boolean,
pollId: String,
name: String
): PollMainDialogFragment {
val args = Bundle()
args.putParcelable(KEY_USER_ENTITY, user)
args.putString(KEY_ROOM_TOKEN, roomTokenParam)
args.putBoolean(KEY_OWNER_OR_MODERATOR, isOwnerOrModerator)
args.putString(KEY_POLL_ID, pollId)
args.putString(KEY_POLL_TITLE, name)
val fragment = PollMainDialogFragment()

View File

@ -33,8 +33,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import autodagger.AutoInjector
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.DialogPollResultsBinding
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.polls.adapters.PollResultHeaderItem
import com.nextcloud.talk.polls.adapters.PollResultItemClickListener
import com.nextcloud.talk.polls.adapters.PollResultsAdapter
@ -51,7 +51,7 @@ class PollResultsFragment : Fragment(), PollResultItemClickListener {
private lateinit var parentViewModel: PollMainViewModel
lateinit var viewModel: PollResultsViewModel
lateinit var user: UserEntity
lateinit var user: User
lateinit var binding: DialogPollResultsBinding
@ -108,7 +108,7 @@ class PollResultsFragment : Fragment(), PollResultItemClickListener {
if (showEditButton) {
binding.editVoteButton.visibility = View.VISIBLE
binding.editVoteButton.setOnClickListener {
parentViewModel.edit()
parentViewModel.editVotes()
}
} else {
binding.editVoteButton.visibility = View.GONE
@ -142,7 +142,7 @@ class PollResultsFragment : Fragment(), PollResultItemClickListener {
@JvmStatic
fun newInstance(
user: UserEntity
user: User
): PollResultsFragment {
val args = Bundle()
args.putParcelable(KEY_USER_ENTITY, user)

View File

@ -52,24 +52,29 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito
private lateinit var roomToken: String
private lateinit var pollId: String
private var editPoll: Boolean = false
private var isOwnerOrModerator: Boolean = false
private var editVotes: Boolean = false
sealed interface ViewState
object InitialState : ViewState
open class PollVoteState(
val poll: Poll,
val showVotersAmount: Boolean,
val showEndPollButton: Boolean
) : ViewState
open class PollVoteHiddenState(
val poll: Poll,
val showVotersAmount: Boolean,
val showEndPollButton: Boolean
) : ViewState
open class PollResultState(
val poll: Poll,
val showEditButton: Boolean,
val showEndPollButton: Boolean
val showVotersAmount: Boolean,
val showEndPollButton: Boolean,
val showEditButton: Boolean
) : ViewState
private val _viewState: MutableLiveData<ViewState> = MutableLiveData(InitialState)
@ -89,8 +94,8 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito
loadPoll()
}
fun edit() {
editPoll = true
fun editVotes() {
editVotes = true
loadPoll()
}
@ -130,28 +135,34 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito
}
override fun onComplete() {
val showEndPollButton = poll.status == Poll.STATUS_OPEN && isPollCreatedByCurrentUser(poll)
val showEndPollButton = showEndPollButton(poll)
val showVotersAmount = showVotersAmount(poll)
if (votedForOpenHiddenPoll(poll)) {
_viewState.value = PollVoteHiddenState(poll, showEndPollButton)
} else if (editPoll && poll.status == Poll.STATUS_OPEN) {
_viewState.value = PollVoteState(poll, showEndPollButton)
editPoll = false
_viewState.value = PollVoteHiddenState(poll, showVotersAmount, showEndPollButton)
} else if (editVotes && poll.status == Poll.STATUS_OPEN) {
_viewState.value = PollVoteState(poll, false, showEndPollButton)
editVotes = false
} else if (poll.status == Poll.STATUS_CLOSED || poll.votedSelf?.isNotEmpty() == true) {
setPollResultState(poll)
val showEditButton = poll.status == Poll.STATUS_OPEN && poll.resultMode == Poll.RESULT_MODE_PUBLIC
_viewState.value = PollResultState(poll, showVotersAmount, showEndPollButton, showEditButton)
} else if (poll.votedSelf.isNullOrEmpty()) {
_viewState.value = PollVoteState(poll, showEndPollButton)
_viewState.value = PollVoteState(poll, showVotersAmount, showEndPollButton)
} else {
Log.w(TAG, "unknown poll state")
}
}
}
private fun setPollResultState(poll: Poll) {
val showEditButton = poll.status == Poll.STATUS_OPEN && poll.resultMode == Poll.RESULT_MODE_PUBLIC
val showEndPollButton = poll.status == Poll.STATUS_OPEN && isPollCreatedByCurrentUser(poll)
private fun showEndPollButton(poll: Poll): Boolean {
return poll.status == Poll.STATUS_OPEN && (isPollCreatedByCurrentUser(poll) || isOwnerOrModerator)
}
_viewState.value = PollResultState(poll, showEditButton, showEndPollButton)
private fun showVotersAmount(poll: Poll): Boolean {
return votedForPublicPoll(poll) ||
poll.status == Poll.STATUS_CLOSED ||
isOwnerOrModerator ||
isPollCreatedByCurrentUser(poll)
}
private fun votedForOpenHiddenPoll(poll: Poll): Boolean {
@ -160,10 +171,19 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito
poll.votedSelf?.isNotEmpty() == true
}
private fun votedForPublicPoll(poll: Poll): Boolean {
return poll.resultMode == Poll.RESULT_MODE_PUBLIC &&
poll.votedSelf?.isNotEmpty() == true
}
private fun isPollCreatedByCurrentUser(poll: Poll): Boolean {
return userUtils.currentUser?.userId == poll.actorId
}
fun setIsOwnerOrModerator(ownerOrModerator: Boolean) {
isOwnerOrModerator = ownerOrModerator
}
companion object {
private val TAG = PollMainViewModel::class.java.simpleName
}

View File

@ -49,13 +49,51 @@
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/poll_results_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textColor="@color/low_emphasis_text"
android:text="@string/polls_results_subtitle"
android:visibility="gone"
tools:visibility="visible"/>
<TextView
android:id="@+id/poll_results_subtitle_seperator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textColor="@color/low_emphasis_text"
android:text=" - "
android:visibility="gone"
tools:visibility="visible"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/poll_votes_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textColor="@color/low_emphasis_text"
tools:text="93 votes" />
</LinearLayout>
<TextView
android:id="@+id/poll_details_text"
android:id="@+id/poll_voted_hidden"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textColor="@color/low_emphasis_text"
tools:text="Poll results - 93 votes" />
android:text="@string/polls_private_voted" />
<FrameLayout
android:id="@+id/message_poll_content_fragment"

View File

@ -537,12 +537,13 @@
<string name="message_search_begin_empty">No search results</string>
<!-- Polls -->
<string name="polls_amount_voters">Poll results - %1$s votes</string>
<string name="polls_amount_voters">%1$s voters</string>
<string name="polls_add_option">Add Option</string>
<string name="polls_private_voted">You successfully voted for this private poll.</string>
<string name="polls_end_poll">End Poll</string>
<string name="polls_end_poll_confirm">Do you really want to end this poll? This can\'t be undone.</string>
<string name="polls_max_votes_reached">You can\'t vote with more options for this poll.</string>
<string name="polls_results_subtitle">Results</string>
<string name="title_attachments">Attachments</string>