mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-10 14:24:05 +01:00
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 <dev@mhibbe.de>
This commit is contained in:
parent
ea0b7d07cc
commit
b504af1cd9
@ -491,7 +491,8 @@ data class ChatMessage(
|
||||
REACTION,
|
||||
REACTION_DELETED,
|
||||
REACTION_REVOKED,
|
||||
POLL_VOTED
|
||||
POLL_VOTED,
|
||||
POLL_CLOSED
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -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<ChatMessage.Syst
|
||||
"reaction_deleted" -> REACTION_DELETED
|
||||
"reaction_revoked" -> REACTION_REVOKED
|
||||
"poll_voted" -> POLL_VOTED
|
||||
"poll_closed" -> POLL_CLOSED
|
||||
else -> DUMMY
|
||||
}
|
||||
}
|
||||
@ -227,6 +229,7 @@ class EnumSystemMessageTypeConverter : StringBasedTypeConverter<ChatMessage.Syst
|
||||
REACTION_DELETED -> return "reaction_deleted"
|
||||
REACTION_REVOKED -> return "reaction_revoked"
|
||||
POLL_VOTED -> return "poll_voted"
|
||||
POLL_CLOSED -> return "poll_closed"
|
||||
else -> return ""
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<PollResultViewHolder>() {
|
||||
internal var list: MutableList<PollResultItem> = ArrayList<PollResultItem>()
|
||||
|
||||
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) {
|
||||
|
@ -5,10 +5,6 @@ import io.reactivex.Observable
|
||||
|
||||
interface PollRepository {
|
||||
|
||||
fun getPoll(roomToken: String, pollId: String): Observable<Poll>?
|
||||
|
||||
fun vote(roomToken: String, pollId: String, option: Int): Observable<Poll>?
|
||||
|
||||
fun createPoll(
|
||||
roomToken: String,
|
||||
question: String,
|
||||
@ -16,4 +12,10 @@ interface PollRepository {
|
||||
resultMode: Int,
|
||||
maxVotes: Int
|
||||
): Observable<Poll>?
|
||||
|
||||
fun getPoll(roomToken: String, pollId: String): Observable<Poll>?
|
||||
|
||||
fun vote(roomToken: String, pollId: String, option: Int): Observable<Poll>?
|
||||
|
||||
fun closePoll(roomToken: String, pollId: String): Observable<Poll>?
|
||||
}
|
||||
|
@ -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<Poll> {
|
||||
|
||||
return ncApi.closePoll(
|
||||
credentials,
|
||||
ApiUtils.getUrlForPoll(
|
||||
currentUserProvider.currentUser?.baseUrl,
|
||||
roomToken,
|
||||
pollId
|
||||
),
|
||||
).map { mapToPoll(it.ocs?.data!!) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun mapToPoll(pollResponse: PollResponse): Poll {
|
||||
|
@ -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 {
|
||||
|
@ -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..")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<ViewState> = MutableLiveData(InitialState)
|
||||
val viewState: LiveData<ViewState>
|
||||
@ -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
|
||||
}
|
||||
|
@ -48,6 +48,18 @@
|
||||
app:layout_constraintTop_toBottomOf="@+id/poll_results_list_wrapper"
|
||||
tools:text="Poll results - 93 votes" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/close_vote_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Close"
|
||||
android:theme="@style/Button.Primary"
|
||||
app:cornerRadius="@dimen/button_corner_radius"
|
||||
app:layout_constraintEnd_toStartOf="@+id/edit_vote_button"
|
||||
app:layout_constraintTop_toBottomOf="@+id/poll_results_list_wrapper" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/edit_vote_button"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -30,4 +30,19 @@
|
||||
app:layout_constraintTop_toBottomOf="@+id/poll_option_text"
|
||||
style="?android:attr/progressBarStyleHorizontal" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/poll_option_detail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintStart_toStartOf="@+id/poll_option_text"
|
||||
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>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
Loading…
Reference in New Issue
Block a user