wip: show user avatars for closed public polls

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2022-06-24 23:13:40 +02:00 committed by Andy Scherzinger (Rebase PR Action)
parent fb54b35cf0
commit 318549a63a
10 changed files with 115 additions and 38 deletions

View File

@ -125,6 +125,7 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : MessageH
binding.bubble.setOnClickListener { binding.bubble.setOnClickListener {
val pollVoteDialog = PollMainDialogFragment.newInstance( val pollVoteDialog = PollMainDialogFragment.newInstance(
message.activeUser!!,
roomToken, roomToken,
pollId, pollId,
pollName pollName

View File

@ -141,6 +141,7 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) : Messag
binding.bubble.setOnClickListener { binding.bubble.setOnClickListener {
val pollVoteDialog = PollMainDialogFragment.newInstance( val pollVoteDialog = PollMainDialogFragment.newInstance(
message.activeUser!!,
roomToken, roomToken,
pollId, pollId,
pollName pollName

View File

@ -1,9 +1,10 @@
package com.nextcloud.talk.polls.adapters package com.nextcloud.talk.polls.adapters
class PollResultItem( import com.nextcloud.talk.polls.model.PollDetails
val pollOption: String,
val pollPercent: Int,
val selfVoted: Boolean
// val voters.... class PollResultItem(
val name: String,
val percent: Int,
val selfVoted: Boolean,
val voters: List<PollDetails>?
) )

View File

@ -2,34 +2,106 @@ package com.nextcloud.talk.polls.adapters
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.Typeface import android.graphics.Typeface
import android.text.TextUtils
import android.view.View import android.view.View
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.interfaces.DraweeController
import com.facebook.drawee.view.SimpleDraweeView
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.PollResultItemBinding import com.nextcloud.talk.databinding.PollResultItemBinding
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 PollResultViewHolder( class PollResultViewHolder(
private val binding: PollResultItemBinding, private val user: UserEntity,
private val showDetails: Boolean, private val binding: PollResultItemBinding
) : RecyclerView.ViewHolder(binding.root) {
) : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun bind(pollResultItem: PollResultItem, clickListener: PollResultItemClickListener) { fun bind(pollResultItem: PollResultItem, clickListener: PollResultItemClickListener) {
binding.root.setOnClickListener { clickListener.onClick(pollResultItem) } binding.root.setOnClickListener { clickListener.onClick(pollResultItem) }
binding.pollOptionText.text = pollResultItem.pollOption // binding.root.setOnClickListener { clickListener.onClick(pollResultItem) }
binding.pollOptionPercentText.text = pollResultItem.pollPercent.toString() + "%"
binding.pollOptionText.text = pollResultItem.name
binding.pollOptionPercentText.text = "${pollResultItem.percent}%"
if (pollResultItem.selfVoted) { if (pollResultItem.selfVoted) {
binding.pollOptionText.setTypeface(null, Typeface.BOLD) binding.pollOptionText.setTypeface(null, Typeface.BOLD)
binding.pollOptionPercentText.setTypeface(null, Typeface.BOLD) binding.pollOptionPercentText.setTypeface(null, Typeface.BOLD)
} }
binding.pollOptionBar.progress = pollResultItem.pollPercent binding.pollOptionBar.progress = pollResultItem.percent
if (showDetails) { if (!pollResultItem.voters.isNullOrEmpty()) {
binding.pollOptionDetail.visibility = View.VISIBLE binding.pollOptionDetail.visibility = View.VISIBLE
val lp = LinearLayout.LayoutParams(
90,
70
)
pollResultItem.voters.forEach {
val avatar = SimpleDraweeView(binding.root.context)
avatar.layoutParams = lp
val roundingParams = RoundingParams.fromCornersRadius(5f)
roundingParams.roundAsCircle = true
avatar.hierarchy.roundingParams = roundingParams
avatar.controller = getAvatarDraweeController(it)
binding.pollOptionDetail.addView(avatar)
}
} else { } else {
binding.pollOptionDetail.visibility = View.GONE binding.pollOptionDetail.visibility = View.GONE
} }
} }
private fun getAvatarDraweeController(pollDetail: PollDetails): DraweeController? {
if (pollDetail.actorType == "guests") {
var displayName = NextcloudTalkApplication.sharedApplication?.resources?.getString(R.string.nc_guest)
if (!TextUtils.isEmpty(pollDetail.actorDisplayName)) {
displayName = pollDetail.actorDisplayName!!
}
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
// .setOldController(binding.avatar.controller)
.setAutoPlayAnimations(true)
.setImageRequest(
DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForGuestAvatar(
user.baseUrl,
displayName,
false
),
null
)
)
.build()
return draweeController
} else if (pollDetail.actorType == "users") {
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
// .setOldController(binding.avatar.controller)
.setAutoPlayAnimations(true)
.setImageRequest(
DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatar(
user.baseUrl,
pollDetail.actorId,
false
),
null
)
)
.build()
return draweeController
}
return null
}
} }

View File

@ -4,20 +4,22 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.nextcloud.talk.databinding.PollResultItemBinding import com.nextcloud.talk.databinding.PollResultItemBinding
import com.nextcloud.talk.models.database.UserEntity
class PollResultsAdapter( class PollResultsAdapter(
private val user: UserEntity,
private val clickListener: PollResultItemClickListener, private val clickListener: PollResultItemClickListener,
private val showDetails: Boolean
) : RecyclerView.Adapter<PollResultViewHolder>() { ) : RecyclerView.Adapter<PollResultViewHolder>() {
internal var list: MutableList<PollResultItem> = ArrayList<PollResultItem>() internal var list: MutableList<PollResultItem> = ArrayList<PollResultItem>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PollResultViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PollResultViewHolder {
val itemBinding = PollResultItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) val itemBinding = PollResultItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return PollResultViewHolder(itemBinding, showDetails) return PollResultViewHolder(user, itemBinding)
} }
override fun onBindViewHolder(holder: PollResultViewHolder, position: Int) { override fun onBindViewHolder(holder: PollResultViewHolder, position: Int) {
holder.bind(list[position], clickListener) val pollResultItem = list[position]
holder.bind(pollResultItem, clickListener)
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {

View File

@ -13,12 +13,14 @@ import autodagger.AutoInjector
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.DialogPollMainBinding 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.model.Poll
import com.nextcloud.talk.polls.viewmodels.PollMainViewModel import com.nextcloud.talk.polls.viewmodels.PollMainViewModel
import javax.inject.Inject import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class PollMainDialogFragment( class PollMainDialogFragment(
private val user: UserEntity,
private val pollId: String, private val pollId: String,
private val roomToken: String, private val roomToken: String,
private val pollTitle: String private val pollTitle: String
@ -91,6 +93,7 @@ class PollMainDialogFragment(
initVotersAmount(poll.numVoters) initVotersAmount(poll.numVoters)
val contentFragment = PollResultsFragment( val contentFragment = PollResultsFragment(
user,
viewModel, viewModel,
roomToken, roomToken,
pollId pollId
@ -114,9 +117,10 @@ class PollMainDialogFragment(
companion object { companion object {
@JvmStatic @JvmStatic
fun newInstance( fun newInstance(
user: UserEntity,
roomTokenParam: String, roomTokenParam: String,
pollId: String, pollId: String,
name: String name: String
): PollMainDialogFragment = PollMainDialogFragment(pollId, roomTokenParam, name) ): PollMainDialogFragment = PollMainDialogFragment(user, pollId, roomTokenParam, name)
} }
} }

View File

@ -32,6 +32,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import autodagger.AutoInjector import autodagger.AutoInjector
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.DialogPollResultsBinding import com.nextcloud.talk.databinding.DialogPollResultsBinding
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.polls.adapters.PollResultItem import com.nextcloud.talk.polls.adapters.PollResultItem
import com.nextcloud.talk.polls.adapters.PollResultItemClickListener import com.nextcloud.talk.polls.adapters.PollResultItemClickListener
import com.nextcloud.talk.polls.adapters.PollResultsAdapter import com.nextcloud.talk.polls.adapters.PollResultsAdapter
@ -42,6 +43,7 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class PollResultsFragment( class PollResultsFragment(
private val user: UserEntity,
private val parentViewModel: PollMainViewModel, private val parentViewModel: PollMainViewModel,
private val roomToken: String, private val roomToken: String,
private val pollId: String private val pollId: String
@ -78,7 +80,7 @@ class PollResultsFragment(
parentViewModel.viewState.observe(viewLifecycleOwner) { state -> parentViewModel.viewState.observe(viewLifecycleOwner) { state ->
if (state is PollMainViewModel.PollResultState) { if (state is PollMainViewModel.PollResultState) {
initAdapter(state.showParticipants) initAdapter()
initPollResults(state.poll) initPollResults(state.poll)
initEditButton(state.showEditButton) initEditButton(state.showEditButton)
initCloseButton(state.showCloseButton) initCloseButton(state.showCloseButton)
@ -86,8 +88,8 @@ class PollResultsFragment(
} }
} }
private fun initAdapter(showParticipants: Boolean) { private fun initAdapter() {
adapter = PollResultsAdapter(this, showParticipants) adapter = PollResultsAdapter(user, this)
_binding?.pollResultsList?.adapter = adapter _binding?.pollResultsList?.adapter = adapter
_binding?.pollResultsList?.layoutManager = LinearLayoutManager(context) _binding?.pollResultsList?.layoutManager = LinearLayoutManager(context)
} }
@ -98,15 +100,15 @@ class PollResultsFragment(
val oneVoteInPercent = 100 / votersAmount // TODO: poll.numVoters when fixed on api val oneVoteInPercent = 100 / votersAmount // TODO: poll.numVoters when fixed on api
poll.options?.forEachIndexed { index, option -> poll.options?.forEachIndexed { index, option ->
val votersForThisOption = poll.details.filter { it.optionId == index }.size val votersForThisOption = poll.details.filter { it.optionId == index }
val optionsPercent = oneVoteInPercent * votersForThisOption val optionsPercent = oneVoteInPercent * votersForThisOption.size
val pollResultItem = PollResultItem( val pollResultItem = PollResultItem(
option, option,
optionsPercent, optionsPercent,
isOptionSelfVoted(poll, index) isOptionSelfVoted(poll, index),
votersForThisOption
) )
// TODO add participants to PollResultItem
adapter?.list?.add(pollResultItem) adapter?.list?.add(pollResultItem)
} }
} else if (poll.votes != null) { } else if (poll.votes != null) {
@ -114,16 +116,17 @@ class PollResultsFragment(
val oneVoteInPercent = 100 / votersAmount val oneVoteInPercent = 100 / votersAmount
poll.options?.forEachIndexed { index, option -> poll.options?.forEachIndexed { index, option ->
var votersForThisOption = poll.votes.filter { it.key.toInt() == index }[index.toString()] var votersAmountForThisOption = poll.votes.filter { it.key.toInt() == index }[index.toString()]
if (votersForThisOption == null) { if (votersAmountForThisOption == null) {
votersForThisOption = 0 votersAmountForThisOption = 0
} }
val optionsPercent = oneVoteInPercent * votersForThisOption val optionsPercent = oneVoteInPercent * votersAmountForThisOption
val pollResultItem = PollResultItem( val pollResultItem = PollResultItem(
option, option,
optionsPercent, optionsPercent,
isOptionSelfVoted(poll, index) isOptionSelfVoted(poll, index),
null
) )
adapter?.list?.add(pollResultItem) adapter?.list?.add(pollResultItem)
} }

View File

@ -48,7 +48,6 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito
open class PollResultState( open class PollResultState(
val poll: Poll, val poll: Poll,
val showParticipants: Boolean,
val showEditButton: Boolean, val showEditButton: Boolean,
val showCloseButton: Boolean val showCloseButton: Boolean
) : ViewState ) : ViewState
@ -129,11 +128,10 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito
} }
private fun setPollResultState(poll: Poll) { private fun setPollResultState(poll: Poll) {
val showDetails = poll.status == Poll.STATUS_CLOSED && poll.resultMode == Poll.RESULT_MODE_PUBLIC
val showEditButton = poll.status == Poll.STATUS_OPEN && poll.resultMode == Poll.RESULT_MODE_PUBLIC val showEditButton = poll.status == Poll.STATUS_OPEN && poll.resultMode == Poll.RESULT_MODE_PUBLIC
val showCloseButton = poll.status == Poll.STATUS_OPEN && isPollCreatedByCurrentUser(poll) val showCloseButton = poll.status == Poll.STATUS_OPEN && isPollCreatedByCurrentUser(poll)
_viewState.value = PollResultState(poll, showDetails, showEditButton, showCloseButton) _viewState.value = PollResultState(poll, showEditButton, showCloseButton)
} }
private fun votedForOpenHiddenPoll(poll: Poll): Boolean { private fun votedForOpenHiddenPoll(poll: Poll): Boolean {

View File

@ -26,7 +26,7 @@
<LinearLayout <LinearLayout
android:id="@+id/poll_results_list_wrapper" android:id="@+id/poll_results_list_wrapper"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="288dp" android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">

View File

@ -38,11 +38,6 @@
app:layout_constraintStart_toStartOf="@+id/poll_option_text" app:layout_constraintStart_toStartOf="@+id/poll_option_text"
app:layout_constraintTop_toBottomOf="@+id/poll_option_bar"> app:layout_constraintTop_toBottomOf="@+id/poll_option_bar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="here the details..." />
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>