poll creation: add logic to enable/disable buttons

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2022-06-21 16:52:17 +02:00 committed by Andy Scherzinger (Rebase PR Action)
parent 8148bfaa65
commit ea0b7d07cc
5 changed files with 82 additions and 45 deletions

View File

@ -31,11 +31,14 @@ class PollCreateOptionViewHolder(
itemsListener.onRemoveOptionsItemClick(pollCreateOptionItem, position) itemsListener.onRemoveOptionsItemClick(pollCreateOptionItem, position)
} }
textListener = getTextWatcher(pollCreateOptionItem) textListener = getTextWatcher(pollCreateOptionItem, itemsListener)
binding.pollOptionText.addTextChangedListener(textListener) binding.pollOptionText.addTextChangedListener(textListener)
} }
private fun getTextWatcher(pollCreateOptionItem: PollCreateOptionItem) = private fun getTextWatcher(
pollCreateOptionItem: PollCreateOptionItem,
itemsListener: PollCreateOptionsItemListener
) =
object : TextWatcher { object : TextWatcher {
override fun afterTextChanged(s: Editable) { override fun afterTextChanged(s: Editable) {
// unused atm // unused atm
@ -47,6 +50,8 @@ class PollCreateOptionViewHolder(
override fun onTextChanged(option: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(option: CharSequence, start: Int, before: Int, count: Int) {
pollCreateOptionItem.pollOption = option.toString() pollCreateOptionItem.pollOption = option.toString()
itemsListener.onOptionsItemTextChanged(pollCreateOptionItem)
} }
} }
} }

View File

@ -3,4 +3,6 @@ package com.nextcloud.talk.polls.adapters
interface PollCreateOptionsItemListener { interface PollCreateOptionsItemListener {
fun onRemoveOptionsItemClick(pollCreateOptionItem: PollCreateOptionItem, position: Int) fun onRemoveOptionsItemClick(pollCreateOptionItem: PollCreateOptionItem, position: Int)
fun onOptionsItemTextChanged(pollCreateOptionItem: PollCreateOptionItem)
} }

View File

@ -5,14 +5,17 @@ import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import autodagger.AutoInjector import autodagger.AutoInjector
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.DialogPollCreateBinding import com.nextcloud.talk.databinding.DialogPollCreateBinding
import com.nextcloud.talk.polls.adapters.PollCreateOptionItem import com.nextcloud.talk.polls.adapters.PollCreateOptionItem
@ -78,6 +81,7 @@ class PollCreateDialogFragment(
private fun setupListeners() { private fun setupListeners() {
binding.pollAddOptionsItem.setOnClickListener { binding.pollAddOptionsItem.setOnClickListener {
viewModel.addOption() viewModel.addOption()
adapter?.itemCount?.minus(1)?.let { it -> binding.pollCreateOptionsList.scrollToPosition(it) }
} }
binding.pollDismiss.setOnClickListener { binding.pollDismiss.setOnClickListener {
@ -117,41 +121,32 @@ class PollCreateDialogFragment(
private fun setupStateObserver() { private fun setupStateObserver() {
viewModel.viewState.observe(viewLifecycleOwner) { state -> viewModel.viewState.observe(viewLifecycleOwner) { state ->
when (state) { when (state) {
// PollCreateViewModel.InitialState -> showInitial()
is PollCreateViewModel.PollCreatedState -> dismiss() is PollCreateViewModel.PollCreatedState -> dismiss()
is PollCreateViewModel.PollCreationFailedState -> dismiss() is PollCreateViewModel.PollCreationFailedState -> showError()
is PollCreateViewModel.PollCreatingState -> updateDialog(state) is PollCreateViewModel.PollCreationState -> updateButtons(state)
} }
} }
// viewModel.state.observe(this) { state ->
// when (state) {
// MessageSearchViewModel.InitialState -> showInitial()
// MessageSearchViewModel.EmptyState -> showEmpty()
// is MessageSearchViewModel.LoadedState -> showLoaded(state)
// MessageSearchViewModel.LoadingState -> showLoading()
// MessageSearchViewModel.ErrorState -> showError()
// is MessageSearchViewModel.FinishedState -> onFinish()
// }
// }
} }
private fun updateDialog(state: PollCreateViewModel.PollCreatingState) { private fun updateButtons(state: PollCreateViewModel.PollCreationState) {
// binding.pollCreateQuestion.setText(state.question) binding.pollAddOptionsItem.isEnabled = state.enableAddOptionButton
// binding.pollCreateButton.isEnabled = state.enableCreatePollButton
// adapter!!.updateOptionsList(state.options)
//
// binding.pollPrivatePollCheckbox.isChecked = state.privatePoll
// binding.pollMultipleAnswersCheckbox.isChecked = state.multipleAnswer
} }
private fun showInitial() { private fun showError() {
binding.pollCreateButton.isEnabled = false dismiss()
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
Log.e(TAG, "Failed to create poll")
} }
override fun onRemoveOptionsItemClick(pollCreateOptionItem: PollCreateOptionItem, position: Int) { override fun onRemoveOptionsItemClick(pollCreateOptionItem: PollCreateOptionItem, position: Int) {
viewModel.removeOption(pollCreateOptionItem) viewModel.removeOption(pollCreateOptionItem)
} }
override fun onOptionsItemTextChanged(pollCreateOptionItem: PollCreateOptionItem) {
viewModel.optionsItemTextChanged()
}
/** /**
* Fragment creator * Fragment creator
*/ */

View File

@ -16,10 +16,14 @@ class PollCreateViewModel @Inject constructor(private val repository: PollReposi
private lateinit var roomToken: String private lateinit var roomToken: String
// private var _options: MutableLiveData<ArrayList<PollCreateOptionItem>> = sealed interface ViewState
// MutableLiveData<ArrayList<PollCreateOptionItem>>() open class PollCreationState(val enableAddOptionButton: Boolean, val enableCreatePollButton: Boolean) : ViewState
// val options: LiveData<ArrayList<PollCreateOptionItem>> object PollCreatedState : ViewState
// get() = _options object PollCreationFailedState : ViewState
private val _viewState: MutableLiveData<ViewState> = MutableLiveData(PollCreationState(true, false))
val viewState: LiveData<ViewState>
get() = _viewState
private var _options: MutableLiveData<ArrayList<PollCreateOptionItem>> = private var _options: MutableLiveData<ArrayList<PollCreateOptionItem>> =
MutableLiveData<ArrayList<PollCreateOptionItem>>() MutableLiveData<ArrayList<PollCreateOptionItem>>()
@ -31,27 +35,18 @@ class PollCreateViewModel @Inject constructor(private val repository: PollReposi
get() = _question get() = _question
private var _privatePoll: MutableLiveData<Boolean> = MutableLiveData<Boolean>() private var _privatePoll: MutableLiveData<Boolean> = MutableLiveData<Boolean>()
var privatePoll: LiveData<Boolean> = _privatePoll val privatePoll: LiveData<Boolean>
get() = _privatePoll get() = _privatePoll
private var _multipleAnswer: MutableLiveData<Boolean> = MutableLiveData<Boolean>() private var _multipleAnswer: MutableLiveData<Boolean> = MutableLiveData<Boolean>()
var multipleAnswer: LiveData<Boolean> = _multipleAnswer val multipleAnswer: LiveData<Boolean>
get() = _multipleAnswer get() = _multipleAnswer
sealed interface ViewState
object InitialState : ViewState
open class PollCreatingState() : ViewState
open class PollCreatedState() : ViewState
open class PollCreationFailedState() : ViewState
private val _viewState: MutableLiveData<ViewState> = MutableLiveData(InitialState)
val viewState: LiveData<ViewState>
get() = _viewState
private var disposable: Disposable? = null private var disposable: Disposable? = null
fun initialize(roomToken: String) { fun initialize(roomToken: String) {
this.roomToken = roomToken this.roomToken = roomToken
updateCreationState()
} }
override fun onCleared() { override fun onCleared() {
@ -64,12 +59,14 @@ class PollCreateViewModel @Inject constructor(private val repository: PollReposi
val currentOptions: ArrayList<PollCreateOptionItem> = _options.value ?: ArrayList() val currentOptions: ArrayList<PollCreateOptionItem> = _options.value ?: ArrayList()
currentOptions.add(item) currentOptions.add(item)
_options.value = currentOptions _options.value = currentOptions
updateCreationState()
} }
fun removeOption(item: PollCreateOptionItem) { fun removeOption(item: PollCreateOptionItem) {
val currentOptions: ArrayList<PollCreateOptionItem> = _options.value ?: ArrayList() val currentOptions: ArrayList<PollCreateOptionItem> = _options.value ?: ArrayList()
currentOptions.remove(item) currentOptions.remove(item)
_options.value = currentOptions _options.value = currentOptions
updateCreationState()
} }
fun createPoll() { fun createPoll() {
@ -83,9 +80,9 @@ class PollCreateViewModel @Inject constructor(private val repository: PollReposi
resultMode = 1 resultMode = 1
} }
if (question.value?.isNotEmpty() == true && _options.value?.isNotEmpty() == true) { if (_question.value?.isNotEmpty() == true && _options.value?.isNotEmpty() == true) {
repository.createPoll( repository.createPoll(
roomToken, question.value!!, _options.value!!.map { it.pollOption }, resultMode, roomToken, _question.value!!, _options.value!!.map { it.pollOption }, resultMode,
maxVotes maxVotes
) )
?.doOnSubscribe { disposable = it } ?.doOnSubscribe { disposable = it }
@ -97,6 +94,7 @@ class PollCreateViewModel @Inject constructor(private val repository: PollReposi
fun setQuestion(question: String) { fun setQuestion(question: String) {
_question.value = question _question.value = question
updateCreationState()
} }
fun setPrivatePoll(checked: Boolean) { fun setPrivatePoll(checked: Boolean) {
@ -107,6 +105,44 @@ class PollCreateViewModel @Inject constructor(private val repository: PollReposi
_multipleAnswer.value = checked _multipleAnswer.value = checked
} }
fun optionsItemTextChanged() {
updateCreationState()
}
private fun updateCreationState() {
_viewState.value = PollCreationState(enableAddOptionButton(), enableCreatePollButton())
}
private fun enableCreatePollButton(): Boolean {
return _question.value?.isNotEmpty() == true && atLeastTwoOptionsAreFilled()
}
private fun atLeastTwoOptionsAreFilled(): Boolean {
if (_options.value != null) {
var filledOptions = 0
_options.value?.forEach {
if (it.pollOption.isNotEmpty()) {
filledOptions++
}
if (filledOptions >= 2) {
return true
}
}
}
return false
}
private fun enableAddOptionButton(): Boolean {
if (_options.value != null && _options.value?.size != 0) {
_options.value?.forEach {
if (it.pollOption.isBlank()) {
return false
}
}
}
return true
}
inner class PollObserver : Observer<Poll> { inner class PollObserver : Observer<Poll> {
lateinit var poll: Poll lateinit var poll: Poll
@ -118,11 +154,11 @@ class PollCreateViewModel @Inject constructor(private val repository: PollReposi
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
_viewState.value = PollCreationFailedState() _viewState.value = PollCreationFailedState
} }
override fun onComplete() { override fun onComplete() {
_viewState.value = PollCreatedState() _viewState.value = PollCreatedState
} }
} }

View File

@ -31,7 +31,6 @@
<!-- android:text="@string/nc_create_poll"--> <!-- android:text="@string/nc_create_poll"-->
<!-- android:textStyle="bold"--> <!-- android:textStyle="bold"-->
<!-- android:layout_marginBottom="@dimen/standard_half_margin"/>--> <!-- android:layout_marginBottom="@dimen/standard_half_margin"/>-->
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"