From 40f20c56d6b9e15009670441700ae7dfbeaf3c18 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 14 Jul 2022 14:45:12 +0200 Subject: [PATCH] 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 --- .../messages/IncomingPollMessageViewHolder.kt | 4 +- .../talk/adapters/messages/MessagePayload.kt | 3 +- .../OutcomingPollMessageViewHolder.kt | 4 +- .../talk/controllers/ChatController.kt | 2 +- .../adapters/PollResultVoterViewHolder.kt | 8 +-- .../talk/polls/adapters/PollResultsAdapter.kt | 4 +- .../talk/polls/ui/PollMainDialogFragment.kt | 58 +++++++++++++------ .../talk/polls/ui/PollResultsFragment.kt | 8 +-- .../polls/viewmodels/PollMainViewModel.kt | 52 ++++++++++++----- app/src/main/res/layout/dialog_poll_main.xml | 42 +++++++++++++- app/src/main/res/values/strings.xml | 3 +- 11 files changed, 137 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt index 51bab9f80..b6c1744db 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt @@ -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 ) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MessagePayload.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/MessagePayload.kt index 59be4b481..9444eb63b 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MessagePayload.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MessagePayload.kt @@ -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 ) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt index 15b3d8ab0..6583a2719 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt @@ -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 ) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index 0927abf94..d271fc8dc 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -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, diff --git a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultVoterViewHolder.kt b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultVoterViewHolder.kt index f88f9acf3..756887c4b 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultVoterViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultVoterViewHolder.kt @@ -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() diff --git a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultsAdapter.kt b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultsAdapter.kt index f70f8393c..9fa3b1dc2 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultsAdapter.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultsAdapter.kt @@ -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() { internal var list: MutableList = ArrayList() diff --git a/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt index 99a694bfb..6ca06436f 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt @@ -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() diff --git a/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt b/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt index 451a9058b..39bcfb918 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt @@ -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) diff --git a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt index 8f5a43347..44c2c8ffe 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt @@ -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 = 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 } diff --git a/app/src/main/res/layout/dialog_poll_main.xml b/app/src/main/res/layout/dialog_poll_main.xml index cbb01106c..70f40d028 100644 --- a/app/src/main/res/layout/dialog_poll_main.xml +++ b/app/src/main/res/layout/dialog_poll_main.xml @@ -49,13 +49,51 @@ + + + + + + + + + + + + + android:text="@string/polls_private_voted" /> No search results - Poll results - %1$s votes + %1$s voters Add Option You successfully voted for this private poll. End Poll Do you really want to end this poll? This can\'t be undone. You can\'t vote with more options for this poll. + Results Attachments