瀏覽代碼

Add various methods to control checked item states of a built dialog. Resolves #1596.

Aidan Follestad 6 年之前
父節點
當前提交
92df60fae9

+ 16 - 0
core/src/main/java/com/afollestad/materialdialogs/internal/list/DialogAdapter.kt

@@ -14,5 +14,21 @@ interface DialogAdapter<IT, SL> {
 
   fun disableItems(indices: IntArray)
 
+  fun checkItems(indices: IntArray)
+
+  fun uncheckItems(indices: IntArray)
+
+  fun toggleItems(indices: IntArray)
+
+  fun checkAllItems()
+
+  fun uncheckAllItems()
+
+  fun toggleAllChecked()
+
+  fun isItemChecked(index: Int): Boolean
+
+  fun getItemCount(): Int
+
   fun positiveButtonClicked()
 }

+ 48 - 0
core/src/main/java/com/afollestad/materialdialogs/internal/list/MultiChoiceDialogAdapter.kt

@@ -18,8 +18,10 @@ import com.afollestad.materialdialogs.actions.hasActionButtons
 import com.afollestad.materialdialogs.actions.setActionButtonEnabled
 import com.afollestad.materialdialogs.list.MultiChoiceListener
 import com.afollestad.materialdialogs.list.getItemSelector
+import com.afollestad.materialdialogs.utils.appendAll
 import com.afollestad.materialdialogs.utils.inflate
 import com.afollestad.materialdialogs.utils.pullIndices
+import com.afollestad.materialdialogs.utils.removeAll
 
 /** @author Aidan Follestad (afollestad) */
 internal class MultiChoiceViewHolder(
@@ -148,4 +150,50 @@ internal class MultiChoiceDialogAdapter(
     this.disabledIndices = indices
     notifyDataSetChanged()
   }
+
+  override fun checkItems(indices: IntArray) {
+    val existingSelection = this.currentSelection
+    val indicesToAdd = indices.filter { !existingSelection.contains(it) }
+    this.currentSelection = this.currentSelection.appendAll(indicesToAdd)
+  }
+
+  override fun uncheckItems(indices: IntArray) {
+    val existingSelection = this.currentSelection
+    val indicesToAdd = indices.filter { existingSelection.contains(it) }
+    this.currentSelection = this.currentSelection.removeAll(indicesToAdd)
+  }
+
+  override fun toggleItems(indices: IntArray) {
+    val newSelection = this.currentSelection.toMutableList()
+    for (target in indices) {
+      if (this.disabledIndices.contains(target)) continue
+      if (newSelection.contains(target)) {
+        newSelection.remove(target)
+      } else {
+        newSelection.add(target)
+      }
+    }
+    this.currentSelection = newSelection.toIntArray()
+  }
+
+  override fun checkAllItems() {
+    val existingSelection = this.currentSelection
+    val wholeRange = IntArray(itemCount) { it }
+    val indicesToAdd = wholeRange.filter { !existingSelection.contains(it) }
+    this.currentSelection = this.currentSelection.appendAll(indicesToAdd)
+  }
+
+  override fun uncheckAllItems() {
+    this.currentSelection = intArrayOf()
+  }
+
+  override fun toggleAllChecked() {
+    if (this.currentSelection.isEmpty()) {
+      checkAllItems()
+    } else {
+      uncheckAllItems()
+    }
+  }
+
+  override fun isItemChecked(index: Int) = this.currentSelection.contains(index)
 }

+ 14 - 0
core/src/main/java/com/afollestad/materialdialogs/internal/list/PlainListDialogAdapter.kt

@@ -119,4 +119,18 @@ internal class PlainListDialogAdapter(
     this.disabledIndices = indices
     notifyDataSetChanged()
   }
+
+  override fun checkItems(indices: IntArray) = Unit
+
+  override fun uncheckItems(indices: IntArray) = Unit
+
+  override fun toggleItems(indices: IntArray) = Unit
+
+  override fun checkAllItems() = Unit
+
+  override fun uncheckAllItems() = Unit
+
+  override fun toggleAllChecked() = Unit
+
+  override fun isItemChecked(index: Int) = false
 }

+ 30 - 0
core/src/main/java/com/afollestad/materialdialogs/internal/list/SingleChoiceDialogAdapter.kt

@@ -129,4 +129,34 @@ internal class SingleChoiceDialogAdapter(
     this.disabledIndices = indices
     notifyDataSetChanged()
   }
+
+  override fun checkItems(indices: IntArray) {
+    val targetIndex = if (indices.isNotEmpty()) indices[0] else -1
+    if (this.disabledIndices.contains(targetIndex)) return
+    this.currentSelection = targetIndex
+  }
+
+  override fun uncheckItems(indices: IntArray) {
+    val targetIndex = if (indices.isNotEmpty()) indices[0] else -1
+    if (this.disabledIndices.contains(targetIndex)) return
+    this.currentSelection = -1
+  }
+
+  override fun toggleItems(indices: IntArray) {
+    val targetIndex = if (indices.isNotEmpty()) indices[0] else -1
+    if (this.disabledIndices.contains(targetIndex)) return
+    if (indices.isEmpty() || this.currentSelection == targetIndex) {
+      this.currentSelection = -1
+    } else {
+      this.currentSelection = targetIndex
+    }
+  }
+
+  override fun checkAllItems() = Unit
+
+  override fun uncheckAllItems() = Unit
+
+  override fun toggleAllChecked() = Unit
+
+  override fun isItemChecked(index: Int) = this.currentSelection == index
 }

+ 73 - 0
core/src/main/java/com/afollestad/materialdialogs/list/DialogMultiChoiceExt.kt

@@ -13,6 +13,7 @@ import com.afollestad.materialdialogs.MaterialDialog
 import com.afollestad.materialdialogs.WhichButton.POSITIVE
 import com.afollestad.materialdialogs.actions.setActionButtonEnabled
 import com.afollestad.materialdialogs.assertOneSet
+import com.afollestad.materialdialogs.internal.list.DialogAdapter
 import com.afollestad.materialdialogs.internal.list.MultiChoiceDialogAdapter
 import com.afollestad.materialdialogs.utils.getStringArray
 
@@ -59,3 +60,75 @@ fun MaterialDialog.listItemsMultiChoice(
       )
   )
 }
+
+/** Checks a set of multiple choice list items. */
+fun MaterialDialog.checkItems(indices: IntArray) {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.checkItems(indices)
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't check items on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Unchecks a set of multiple choice list items. */
+fun MaterialDialog.uncheckItems(indices: IntArray) {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.uncheckItems(indices)
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't uncheck items on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Toggles the checked state of a set of multiple choice list items. */
+fun MaterialDialog.toggleItemsChecked(indices: IntArray) {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.toggleItems(indices)
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't toggle checked items on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Checks all multiple choice list items. */
+fun MaterialDialog.checkAllItems() {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.checkAllItems()
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't check all items on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Unchecks all single or multiple choice list items. */
+fun MaterialDialog.uncheckAllItems() {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.uncheckAllItems()
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't uncheck all items on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Toggles the checked state of all multiple choice list items. */
+fun MaterialDialog.toggleAllItemsChecked() {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.toggleAllChecked()
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't uncheck all items on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}

+ 48 - 0
core/src/main/java/com/afollestad/materialdialogs/list/DialogSingleChoiceExt.kt

@@ -13,6 +13,7 @@ import com.afollestad.materialdialogs.MaterialDialog
 import com.afollestad.materialdialogs.WhichButton.POSITIVE
 import com.afollestad.materialdialogs.actions.setActionButtonEnabled
 import com.afollestad.materialdialogs.assertOneSet
+import com.afollestad.materialdialogs.internal.list.DialogAdapter
 import com.afollestad.materialdialogs.internal.list.SingleChoiceDialogAdapter
 import com.afollestad.materialdialogs.utils.getStringArray
 
@@ -59,3 +60,50 @@ fun MaterialDialog.listItemsSingleChoice(
       )
   )
 }
+
+/** Checks a single or multiple choice list item. */
+fun MaterialDialog.checkItem(index: Int) {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.checkItems(intArrayOf(index))
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't check item on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Unchecks a single or multiple choice list item. */
+fun MaterialDialog.uncheckItem(index: Int) {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.uncheckItems(intArrayOf(index))
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't uncheck item on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Checks or unchecks a single or multiple choice list item. */
+fun MaterialDialog.toggleItemChecked(index: Int) {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    adapter.toggleItems(intArrayOf(index))
+    return
+  }
+  throw UnsupportedOperationException(
+      "Can't toggle checked item on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}
+
+/** Returns true if a single or multiple list item is checked. */
+fun MaterialDialog.isItemChecked(index: Int): Boolean {
+  val adapter = getListAdapter()
+  if (adapter is DialogAdapter<*, *>) {
+    return adapter.isItemChecked(index)
+  }
+  throw UnsupportedOperationException(
+      "Can't check if item is checked on adapter: ${adapter?.javaClass?.name ?: "null"}"
+  )
+}

+ 13 - 0
core/src/main/java/com/afollestad/materialdialogs/utils/IntArrayExt.kt

@@ -0,0 +1,13 @@
+package com.afollestad.materialdialogs.utils
+
+internal fun IntArray.appendAll(values: Collection<Int>): IntArray {
+  val mutable = this.toMutableList()
+  mutable.addAll(values)
+  return mutable.toIntArray()
+}
+
+internal fun IntArray.removeAll(values: Collection<Int>): IntArray {
+  val mutable = this.toMutableList()
+  mutable.removeAll { values.contains(it) }
+  return mutable.toIntArray()
+}

+ 7 - 2
sample/src/main/java/com/afollestad/materialdialogssample/MainActivity.kt

@@ -33,6 +33,7 @@ import com.afollestad.materialdialogs.input.input
 import com.afollestad.materialdialogs.list.listItems
 import com.afollestad.materialdialogs.list.listItemsMultiChoice
 import com.afollestad.materialdialogs.list.listItemsSingleChoice
+import com.afollestad.materialdialogs.list.toggleAllItemsChecked
 import kotlinx.android.synthetic.main.activity_main.basic
 import kotlinx.android.synthetic.main.activity_main.basic_buttons
 import kotlinx.android.synthetic.main.activity_main.basic_checkbox_titled_buttons
@@ -360,7 +361,9 @@ class MainActivity : AppCompatActivity() {
         listItemsSingleChoice(R.array.socialNetworks, initialSelection = 2) { _, index, text ->
           toast("Selected item $text at index $index")
         }
-        positiveButton(R.string.choose)
+        noAutoDismiss()
+        positiveButton(R.string.choose) { d -> d.dismiss() }
+        neutralButton(text = "Toggle") { d -> d.toggleAllItemsChecked() }
         debugMode(debugMode)
       }
     }
@@ -409,7 +412,9 @@ class MainActivity : AppCompatActivity() {
         ) { _, indices, text ->
           toast("Selected items ${text.joinToString()} at indices ${indices.joinToString()}")
         }
-        positiveButton(R.string.choose)
+        noAutoDismiss()
+        positiveButton(R.string.choose) { d -> d.dismiss() }
+        neutralButton(text = "Toggle") { d -> d.toggleAllItemsChecked() }
         debugMode(debugMode)
       }
     }