Browse Source

poll creation: add logic to enable/disable buttons

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Marcel Hibbe 3 years ago
parent
commit
ea0b7d07cc

+ 7 - 2
app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionViewHolder.kt

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

+ 2 - 0
app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsItemListener.kt

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

+ 17 - 22
app/src/main/java/com/nextcloud/talk/polls/ui/PollCreateDialogFragment.kt

@@ -5,14 +5,17 @@ import android.app.Dialog
 import android.os.Bundle
 import android.text.Editable
 import android.text.TextWatcher
+import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.Toast
 import androidx.appcompat.app.AlertDialog
 import androidx.fragment.app.DialogFragment
 import androidx.lifecycle.ViewModelProvider
 import androidx.recyclerview.widget.LinearLayoutManager
 import autodagger.AutoInjector
+import com.nextcloud.talk.R
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.databinding.DialogPollCreateBinding
 import com.nextcloud.talk.polls.adapters.PollCreateOptionItem
@@ -78,6 +81,7 @@ class PollCreateDialogFragment(
     private fun setupListeners() {
         binding.pollAddOptionsItem.setOnClickListener {
             viewModel.addOption()
+            adapter?.itemCount?.minus(1)?.let { it -> binding.pollCreateOptionsList.scrollToPosition(it) }
         }
 
         binding.pollDismiss.setOnClickListener {
@@ -117,41 +121,32 @@ class PollCreateDialogFragment(
     private fun setupStateObserver() {
         viewModel.viewState.observe(viewLifecycleOwner) { state ->
             when (state) {
-                // PollCreateViewModel.InitialState -> showInitial()
                 is PollCreateViewModel.PollCreatedState -> dismiss()
-                is PollCreateViewModel.PollCreationFailedState -> dismiss()
-                is PollCreateViewModel.PollCreatingState -> updateDialog(state)
+                is PollCreateViewModel.PollCreationFailedState -> showError()
+                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) {
-        // binding.pollCreateQuestion.setText(state.question)
-        //
-        // adapter!!.updateOptionsList(state.options)
-        //
-        // binding.pollPrivatePollCheckbox.isChecked = state.privatePoll
-        // binding.pollMultipleAnswersCheckbox.isChecked = state.multipleAnswer
+    private fun updateButtons(state: PollCreateViewModel.PollCreationState) {
+        binding.pollAddOptionsItem.isEnabled = state.enableAddOptionButton
+        binding.pollCreateButton.isEnabled = state.enableCreatePollButton
     }
 
-    private fun showInitial() {
-        binding.pollCreateButton.isEnabled = false
+    private fun showError() {
+        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) {
         viewModel.removeOption(pollCreateOptionItem)
     }
 
+    override fun onOptionsItemTextChanged(pollCreateOptionItem: PollCreateOptionItem) {
+        viewModel.optionsItemTextChanged()
+    }
+
     /**
      * Fragment creator
      */

+ 56 - 20
app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollCreateViewModel.kt

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

+ 0 - 1
app/src/main/res/layout/dialog_poll_create.xml

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