From b504af1cd91bf743e3dedecf676dcf72e0599b9a Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 22 Jun 2022 13:33:14 +0200 Subject: [PATCH] add UI logic + close poll system message add close poll button (wip/temporarily?) add "close poll" system message add UI related logic to PollMainViewModel add placeholder for pollDetails in UI Signed-off-by: Marcel Hibbe --- .../talk/models/json/chat/ChatMessage.kt | 3 +- .../EnumSystemMessageTypeConverter.kt | 3 ++ .../polls/adapters/PollResultViewHolder.kt | 10 +++- .../talk/polls/adapters/PollResultsAdapter.kt | 5 +- .../talk/polls/repositories/PollRepository.kt | 10 ++-- .../polls/repositories/PollRepositoryImpl.kt | 12 +++++ .../talk/polls/ui/PollMainDialogFragment.kt | 4 +- .../talk/polls/ui/PollResultsFragment.kt | 51 +++++++++++++------ .../talk/polls/ui/PollVoteFragment.kt | 4 +- .../polls/viewmodels/PollMainViewModel.kt | 35 +++++++++++-- .../main/res/layout/dialog_poll_results.xml | 12 +++++ app/src/main/res/layout/poll_result_item.xml | 15 ++++++ 12 files changed, 131 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt index 312ad14a5..c47293fd6 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt @@ -491,7 +491,8 @@ data class ChatMessage( REACTION, REACTION_DELETED, REACTION_REVOKED, - POLL_VOTED + POLL_VOTED, + POLL_CLOSED } companion object { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt b/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt index 3a8049a78..20e525110 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt @@ -65,6 +65,7 @@ import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.MODERAT import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.OBJECT_SHARED import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PASSWORD_REMOVED import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PASSWORD_SET +import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.POLL_CLOSED import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.POLL_VOTED import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.REACTION import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.REACTION_DELETED @@ -169,6 +170,7 @@ class EnumSystemMessageTypeConverter : StringBasedTypeConverter REACTION_DELETED "reaction_revoked" -> REACTION_REVOKED "poll_voted" -> POLL_VOTED + "poll_closed" -> POLL_CLOSED else -> DUMMY } } @@ -227,6 +229,7 @@ class EnumSystemMessageTypeConverter : StringBasedTypeConverter return "reaction_deleted" REACTION_REVOKED -> return "reaction_revoked" POLL_VOTED -> return "poll_voted" + POLL_CLOSED -> return "poll_closed" else -> return "" } } diff --git a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultViewHolder.kt b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultViewHolder.kt index ce928340d..cee0d95ad 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollResultViewHolder.kt @@ -1,11 +1,13 @@ package com.nextcloud.talk.polls.adapters import android.annotation.SuppressLint +import android.view.View import androidx.recyclerview.widget.RecyclerView import com.nextcloud.talk.databinding.PollResultItemBinding class PollResultViewHolder( - private val binding: PollResultItemBinding + private val binding: PollResultItemBinding, + private val showDetails: Boolean ) : RecyclerView.ViewHolder(binding.root) { @SuppressLint("SetTextI18n") @@ -14,5 +16,11 @@ class PollResultViewHolder( binding.pollOptionText.text = pollResultItem.pollOption binding.pollOptionPercentText.text = pollResultItem.pollPercent.toString() + "%" binding.pollOptionBar.progress = pollResultItem.pollPercent + + if (showDetails) { + binding.pollOptionDetail.visibility = View.VISIBLE + } else { + binding.pollOptionDetail.visibility = View.GONE + } } } 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 8c2471f94..039ec4900 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 @@ -6,13 +6,14 @@ import androidx.recyclerview.widget.RecyclerView import com.nextcloud.talk.databinding.PollResultItemBinding class PollResultsAdapter( - private val clickListener: PollResultItemClickListener + private val clickListener: PollResultItemClickListener, + private val showDetails: Boolean ) : RecyclerView.Adapter() { internal var list: MutableList = ArrayList() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PollResultViewHolder { val itemBinding = PollResultItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return PollResultViewHolder(itemBinding) + return PollResultViewHolder(itemBinding, showDetails) } override fun onBindViewHolder(holder: PollResultViewHolder, position: Int) { diff --git a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt index 4654e170f..b2f9c0cf8 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt @@ -5,10 +5,6 @@ import io.reactivex.Observable interface PollRepository { - fun getPoll(roomToken: String, pollId: String): Observable? - - fun vote(roomToken: String, pollId: String, option: Int): Observable? - fun createPoll( roomToken: String, question: String, @@ -16,4 +12,10 @@ interface PollRepository { resultMode: Int, maxVotes: Int ): Observable? + + fun getPoll(roomToken: String, pollId: String): Observable? + + fun vote(roomToken: String, pollId: String, option: Int): Observable? + + fun closePoll(roomToken: String, pollId: String): Observable? } diff --git a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt index e95843190..3c5d73bb4 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt @@ -102,6 +102,18 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid ).map { mapToPoll(it.ocs?.data!!) } } + override fun closePoll(roomToken: String, pollId: String): Observable { + + return ncApi.closePoll( + credentials, + ApiUtils.getUrlForPoll( + currentUserProvider.currentUser?.baseUrl, + roomToken, + pollId + ), + ).map { mapToPoll(it.ocs?.data!!) } + } + companion object { private fun mapToPoll(pollResponse: PollResponse): Poll { 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 f7bb368c5..3be8fa879 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 @@ -60,7 +60,7 @@ class PollMainDialogFragment( when (state) { PollMainViewModel.InitialState -> {} - is PollMainViewModel.PollVotedState -> { + is PollMainViewModel.PollResultState -> { if (state.poll.resultMode == Poll.RESULT_MODE_HIDDEN) { showVoteFragment() } else { @@ -68,7 +68,7 @@ class PollMainDialogFragment( } } - is PollMainViewModel.PollUnvotedState -> { + is PollMainViewModel.PollVoteState -> { if (state.poll.status == Poll.STATUS_CLOSED) { showResultsFragment() } else { 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 4ed2c9404..1aa27c153 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 @@ -77,26 +77,23 @@ class PollResultsFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - adapter = PollResultsAdapter(this) - _binding?.pollResultsList?.adapter = adapter - _binding?.pollResultsList?.layoutManager = LinearLayoutManager(context) - parentViewModel.viewState.observe(viewLifecycleOwner) { state -> - if (state is PollMainViewModel.PollVotedState && - state.poll.resultMode == Poll.RESULT_MODE_PUBLIC - ) { - + if (state is PollMainViewModel.PollResultState) { + initAdapter(state.showDetails) initPollResults(state.poll) initAmountVotersInfo(state) - initEditButton(state) - } else if (state is PollMainViewModel.PollUnvotedState && - state.poll.status == Poll.STATUS_CLOSED - ) { - Log.d(TAG, "show results also if self never voted") + initEditButton(state.showEditButton) + initCloseButton(state.showCloseButton) } } } + private fun initAdapter(showDetails: Boolean) { + adapter = PollResultsAdapter(this, showDetails) + _binding?.pollResultsList?.adapter = adapter + _binding?.pollResultsList?.layoutManager = LinearLayoutManager(context) + } + private fun initPollResults(poll: Poll) { if (poll.details != null) { val votersAmount = poll.details.size @@ -128,15 +125,26 @@ class PollResultsFragment( } } - private fun initAmountVotersInfo(state: PollMainViewModel.PollVotedState) { + private fun initAmountVotersInfo(state: PollMainViewModel.PollResultState) { _binding?.pollAmountVoters?.text = String.format( resources.getString(R.string.polls_amount_voters), state.poll.numVoters ) } - private fun initEditButton(state: PollMainViewModel.PollVotedState) { - if (state.poll.status == Poll.STATUS_OPEN && state.poll.resultMode == Poll.RESULT_MODE_PUBLIC) { + // private fun initEditButton(state: PollMainViewModel.PollResultState) { + // if (state.poll.status == Poll.STATUS_OPEN && state.poll.resultMode == Poll.RESULT_MODE_PUBLIC) { + // _binding?.editVoteButton?.visibility = View.VISIBLE + // _binding?.editVoteButton?.setOnClickListener { + // parentViewModel.edit() + // } + // } else { + // _binding?.editVoteButton?.visibility = View.GONE + // } + // } + + private fun initEditButton(showEditButton: Boolean) { + if (showEditButton) { _binding?.editVoteButton?.visibility = View.VISIBLE _binding?.editVoteButton?.setOnClickListener { parentViewModel.edit() @@ -146,6 +154,17 @@ class PollResultsFragment( } } + private fun initCloseButton(showCloseButton: Boolean) { + if (showCloseButton) { + _binding?.closeVoteButton?.visibility = View.VISIBLE + _binding?.closeVoteButton?.setOnClickListener { + parentViewModel.closePoll() + } + } else { + _binding?.closeVoteButton?.visibility = View.GONE + } + } + override fun onClick(pollResultItem: PollResultItem) { Log.d(TAG, "click..") } diff --git a/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt b/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt index 0f74d7af6..668650b05 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt @@ -71,7 +71,7 @@ class PollVoteFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) parentViewModel.viewState.observe(viewLifecycleOwner) { state -> - if (state is PollMainViewModel.PollUnvotedState) { + if (state is PollMainViewModel.PollVoteState) { val poll = state.poll binding.radioGroup.removeAllViews() poll.options?.map { option -> @@ -80,7 +80,7 @@ class PollVoteFragment( radioButton.id = index binding.radioGroup.addView(radioButton) } - } else if (state is PollMainViewModel.PollVotedState && state.poll.resultMode == Poll.RESULT_MODE_HIDDEN) { + } else if (state is PollMainViewModel.PollResultState && state.poll.resultMode == Poll.RESULT_MODE_HIDDEN) { Log.d(TAG, "show vote screen also for resultMode hidden poll when already voted") // TODO: other text for submit button } 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 28594beab..8d15d3e4b 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 @@ -6,6 +6,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.nextcloud.talk.polls.model.Poll import com.nextcloud.talk.polls.repositories.PollRepository +import com.nextcloud.talk.utils.database.user.UserUtils import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -25,6 +26,9 @@ import javax.inject.Inject */ class PollMainViewModel @Inject constructor(private val repository: PollRepository) : ViewModel() { + @Inject + lateinit var userUtils: UserUtils + private lateinit var roomToken: String private lateinit var pollId: String @@ -32,8 +36,13 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito sealed interface ViewState object InitialState : ViewState - open class PollUnvotedState(val poll: Poll) : ViewState - open class PollVotedState(val poll: Poll) : ViewState + open class PollVoteState(val poll: Poll) : ViewState + open class PollResultState( + val poll: Poll, + val showDetails: Boolean, + val showEditButton: Boolean, + val showCloseButton: Boolean + ) : ViewState private val _viewState: MutableLiveData = MutableLiveData(InitialState) val viewState: LiveData @@ -65,6 +74,14 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito ?.subscribe(PollObserver()) } + fun closePoll() { + repository.closePoll(roomToken, pollId) + ?.doOnSubscribe { disposable = it } + ?.subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(PollObserver()) + } + override fun onCleared() { super.onCleared() disposable?.dispose() @@ -86,16 +103,24 @@ class PollMainViewModel @Inject constructor(private val repository: PollReposito override fun onComplete() { if (editPoll) { - _viewState.value = PollUnvotedState(poll) + _viewState.value = PollVoteState(poll) editPoll = false } else if (poll.votedSelf.isNullOrEmpty()) { - _viewState.value = PollUnvotedState(poll) + _viewState.value = PollVoteState(poll) } else { - _viewState.value = PollVotedState(poll) + val showEditButton = poll.status == Poll.STATUS_OPEN && poll.resultMode == Poll.RESULT_MODE_PUBLIC + val showDetails = poll.status == Poll.STATUS_CLOSED && poll.resultMode == Poll.RESULT_MODE_PUBLIC + val showCloseButton = poll.status == Poll.STATUS_OPEN && isPollCreatedByCurrentUser(poll) + + _viewState.value = PollResultState(poll, showDetails, showEditButton, showCloseButton) } } } + fun isPollCreatedByCurrentUser(poll: Poll): Boolean { + return userUtils.currentUser?.userId == poll.actorId + } + companion object { private val TAG = PollMainViewModel::class.java.simpleName } diff --git a/app/src/main/res/layout/dialog_poll_results.xml b/app/src/main/res/layout/dialog_poll_results.xml index 77a5d7430..5b8008e31 100644 --- a/app/src/main/res/layout/dialog_poll_results.xml +++ b/app/src/main/res/layout/dialog_poll_results.xml @@ -48,6 +48,18 @@ app:layout_constraintTop_toBottomOf="@+id/poll_results_list_wrapper" tools:text="Poll results - 93 votes" /> + + + + + + + + +