浏览代码

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>
Marcel Hibbe 2 年之前
父节点
当前提交
40f20c56d6

+ 3 - 1
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
                 )

+ 2 - 1
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
 )

+ 3 - 1
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
                 )

+ 1 - 1
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,

+ 4 - 4
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()

+ 2 - 2
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<PollResultViewHolder>() {
     internal var list: MutableList<PollResultItem> = ArrayList()

+ 40 - 18
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()

+ 4 - 4
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)

+ 36 - 16
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<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
     }

+ 40 - 2
app/src/main/res/layout/dialog_poll_main.xml

@@ -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"

+ 2 - 1
app/src/main/res/values/strings.xml

@@ -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>