From 7d8aebe234678b40dba1aca697e2944c72565639 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 13 Jun 2022 14:53:48 +0200 Subject: [PATCH] wip: vote on poll Signed-off-by: Marcel Hibbe --- .../java/com/nextcloud/talk/api/NcApi.java | 3 +- .../com/nextcloud/talk/polls/model/Poll.kt | 9 ++- .../talk/polls/repositories/PollRepository.kt | 2 + .../polls/repositories/PollRepositoryImpl.kt | 23 ++++++-- .../talk/polls/ui/PollMainDialogFragment.kt | 6 +- .../talk/polls/ui/PollVoteFragment.kt | 44 +++++++++----- .../talk/polls/viewmodels/PollViewModel.kt | 19 +++--- .../polls/viewmodels/PollVoteViewModel.kt | 58 ++++++++++++++++++- app/src/main/res/layout/dialog_poll_vote.xml | 2 +- 9 files changed, 134 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index e6f0b8d97..1a0fbd8ed 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -538,7 +538,8 @@ public interface NcApi { @POST Observable votePoll(@Header("Authorization") String authorization, - @Url String url); + @Url String url, + @Query("optionIds[]") List optionIds); @DELETE Observable closePoll(@Header("Authorization") String authorization, diff --git a/app/src/main/java/com/nextcloud/talk/polls/model/Poll.kt b/app/src/main/java/com/nextcloud/talk/polls/model/Poll.kt index 1646618d7..4433ace25 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/model/Poll.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/model/Poll.kt @@ -14,4 +14,11 @@ data class Poll( val votedSelf: List?, val numVoters: Int, val details: List? -) +) { + companion object { + const val STATUS_OPEN: Int = 0 + const val STATUS_CLOSED: Int = 1 + const val RESULT_MODE_PUBLIC: Int = 0 + const val RESULT_MODE_HIDDEN: Int = 1 + } +} 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 37e3d3d4d..cfc8b6d55 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 @@ -6,4 +6,6 @@ import io.reactivex.Observable interface PollRepository { fun getPoll(roomToken: String, pollId: String): Observable? + + fun vote(roomToken: String, pollId: String, option: Int): 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 42142e436..c02f7bd22 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 @@ -33,12 +33,12 @@ import io.reactivex.Observable class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvider: CurrentUserProvider) : PollRepository { - override fun getPoll(roomToken: String, pollId: String): Observable { + val credentials = ApiUtils.getCredentials( + currentUserProvider.currentUser?.username, + currentUserProvider.currentUser?.token + ) - val credentials = ApiUtils.getCredentials( - currentUserProvider.currentUser?.username, - currentUserProvider.currentUser?.token - ) + override fun getPoll(roomToken: String, pollId: String): Observable { return ncApi.getPoll( credentials, @@ -69,6 +69,19 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid // ) } + override fun vote(roomToken: String, pollId: String, option: Int): Observable? { + + return ncApi.votePoll( + credentials, + ApiUtils.getUrlForPoll( + currentUserProvider.currentUser?.baseUrl, + roomToken, + pollId + ), + arrayOf(option).asList() + ).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 3997618c2..8e90e2275 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,11 @@ class PollMainDialogFragment( PollViewModel.InitialState -> {} is PollViewModel.PollClosedState -> TODO() is PollViewModel.PollOpenState -> { - val contentFragment = PollVoteFragment(viewModel) + val contentFragment = PollVoteFragment( + viewModel, + roomToken, + pollId + ) val transaction = childFragmentManager.beginTransaction() transaction.replace(binding.messagePollContentFragment.id, contentFragment) transaction.commit() 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 6e733172b..20a895eaf 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 @@ -37,7 +37,11 @@ import com.nextcloud.talk.polls.viewmodels.PollVoteViewModel import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class PollVoteFragment(private val parentViewModel: PollViewModel) : Fragment() { +class PollVoteFragment( + private val parentViewModel: PollViewModel, + private val roomToken: String, + private val pollId: String +) : Fragment() { @Inject lateinit var viewModelFactory: ViewModelProvider.Factory @@ -70,29 +74,43 @@ class PollVoteFragment(private val parentViewModel: PollViewModel) : Fragment() val poll = state.poll binding.radioGroup.removeAllViews() poll.options?.map { option -> - RadioButton(context) - .apply { text = option } - .also { - it.setOnClickListener { - // todo - Log.d("bb", "click1") - } - } - }?.forEach { - binding.radioGroup.addView(it) + RadioButton(context).apply { text = option } + }?.forEachIndexed { index, radioButton -> + radioButton.id = index + binding.radioGroup.addView(radioButton) } } } + + viewModel.viewState.observe(viewLifecycleOwner) { state -> + when (state) { + PollVoteViewModel.InitialState -> {} + is PollVoteViewModel.PollVoteFailedState -> { + Log.d(TAG, "fail") + } + is PollVoteViewModel.PollVoteSuccessState -> { + parentViewModel.voted() + } + } + } + binding.radioGroup.setOnCheckedChangeListener { group, checkedId -> - // todo set selected in viewmodel + // todo set selected in viewmodel. Log.d("bb", "click") } // todo observe viewmodel checked, set view checked with it - // todo listen to button click, submit + + binding.submitVote.setOnClickListener { + viewModel.vote(roomToken, pollId, binding.radioGroup.checkedRadioButtonId) + } } override fun onDestroyView() { super.onDestroyView() _binding = null } + + companion object { + private val TAG = PollVoteFragment::class.java.simpleName + } } diff --git a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollViewModel.kt b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollViewModel.kt index 751d96f5c..e1d0f65ae 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollViewModel.kt @@ -31,6 +31,7 @@ class PollViewModel @Inject constructor(private val repository: PollRepository) sealed interface ViewState object InitialState : ViewState open class PollOpenState(val poll: Poll) : ViewState + open class PollVotedState(val poll: Poll) : ViewState open class PollClosedState(val poll: Poll) : ViewState private val _viewState: MutableLiveData = MutableLiveData(InitialState) @@ -46,14 +47,9 @@ class PollViewModel @Inject constructor(private val repository: PollRepository) loadPoll() } - // private fun loadPoll() { - // disposable = repository.getPoll(roomToken, pollId) - // ?.subscribeOn(Schedulers.io()) - // ?.observeOn(AndroidSchedulers.mainThread()) - // ?.subscribe { poll -> - // _viewState.value = PollOpenState(poll) - // } - // } + fun voted() { + loadPoll() // TODO load other view + } private fun loadPoll() { repository.getPoll(roomToken, pollId) @@ -83,7 +79,12 @@ class PollViewModel @Inject constructor(private val repository: PollRepository) } override fun onComplete() { - _viewState.value = PollOpenState(poll) + // TODO check attributes and decide if poll is open/closed/selfvoted... + + when (poll.status) { + Poll.STATUS_OPEN -> _viewState.value = PollOpenState(poll) + Poll.STATUS_CLOSED -> _viewState.value = PollClosedState(poll) + } } } diff --git a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollVoteViewModel.kt b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollVoteViewModel.kt index 40bb6594d..7de9f7243 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollVoteViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollVoteViewModel.kt @@ -21,12 +21,31 @@ package com.nextcloud.talk.polls.viewmodels +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import com.nextcloud.talk.polls.model.Poll +import com.nextcloud.talk.polls.repositories.PollRepository +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers import javax.inject.Inject -class PollVoteViewModel @Inject constructor() : ViewModel() { +class PollVoteViewModel @Inject constructor(private val repository: PollRepository) : ViewModel() { + + sealed interface ViewState + object InitialState : ViewState + open class PollVoteSuccessState(val poll: Poll) : ViewState + open class PollVoteFailedState() : ViewState + + private val _viewState: MutableLiveData = MutableLiveData(InitialState) + val viewState: LiveData + get() = _viewState + + private var disposable: Disposable? = null + private val _selectedOptions: MutableLiveData> = MutableLiveData(emptyList()) val selectedOptions: LiveData> get() = _selectedOptions @@ -34,4 +53,41 @@ class PollVoteViewModel @Inject constructor() : ViewModel() { fun selectOption(option: String) { _selectedOptions.value = listOf(option) } + + fun vote(roomToken: String, pollId: String, option: Int) { + repository.vote(roomToken, pollId, option) + ?.doOnSubscribe { disposable = it } + ?.subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(PollObserver()) + } + + override fun onCleared() { + super.onCleared() + disposable?.dispose() + } + + inner class PollObserver : Observer { + + lateinit var poll: Poll + + override fun onSubscribe(d: Disposable) = Unit + + override fun onNext(response: Poll) { + poll = response + } + + override fun onError(e: Throwable) { + Log.d(TAG, "An error occurred: $e") + _viewState.value = PollVoteFailedState() + } + + override fun onComplete() { + _viewState.value = PollVoteSuccessState(poll) + } + } + + companion object { + private val TAG = PollVoteViewModel::class.java.simpleName + } } diff --git a/app/src/main/res/layout/dialog_poll_vote.xml b/app/src/main/res/layout/dialog_poll_vote.xml index 094d756ce..102353541 100644 --- a/app/src/main/res/layout/dialog_poll_vote.xml +++ b/app/src/main/res/layout/dialog_poll_vote.xml @@ -33,7 +33,7 @@