Skip to content

Commit

Permalink
refactor: convert IntegerDialog to AlertDialog
Browse files Browse the repository at this point in the history
adds parameters to input()
* hint
* inputType
* maxLength
* waitForPositiveButton

waitForPositiveButton matches the material dialog UI, but is questionable

`allowEmpty` potentially has a bug if called alongside
`waitForPositiveButton`

Issue 13315
  • Loading branch information
david-allison committed Jan 31, 2024
1 parent c67db1b commit b0b2d52
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class CreateDeckDialog(
positiveButton(R.string.dialog_ok) { onPositiveButtonClicked() }
negativeButton(R.string.dialog_cancel)
setView(R.layout.dialog_generic_text_input)
}.input(prefill = initialDeckName, displayKeyboard = true) { dialog, text ->
}.input(prefill = initialDeckName, displayKeyboard = true, waitForPositiveButton = false) { dialog, text ->
// we need the fully-qualified name for subdecks
val maybeDeckName = fullyQualifyDeckName(dialogText = text)
// if the name is empty, it seems distracting to show an error
Expand Down
39 changes: 18 additions & 21 deletions AnkiDroid/src/main/java/com/ichi2/anki/dialogs/IntegerDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@

package com.ichi2.anki.dialogs

import android.annotation.SuppressLint
import android.os.Bundle
import android.text.InputType
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.callbacks.onShow
import com.afollestad.materialdialogs.input.getInputField
import com.afollestad.materialdialogs.input.input
import androidx.appcompat.app.AlertDialog
import com.ichi2.anki.R
import com.ichi2.anki.analytics.AnalyticsDialogFragment
import com.ichi2.utils.contentNullable
import com.ichi2.utils.displayKeyboard
import com.ichi2.utils.input
import com.ichi2.utils.negativeButton
import com.ichi2.utils.positiveButton
import com.ichi2.utils.show
import com.ichi2.utils.title
import java.util.function.Consumer

open class IntegerDialog : AnalyticsDialogFragment() {
Expand All @@ -45,24 +44,22 @@ open class IntegerDialog : AnalyticsDialogFragment() {
arguments = args
}

override fun onCreateDialog(savedInstanceState: Bundle?): MaterialDialog {
override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog {
super.onCreateDialog(savedInstanceState)
@SuppressLint("CheckResult")
val show = MaterialDialog(requireActivity()).show {
return AlertDialog.Builder(requireActivity()).show {
title(text = requireArguments().getString("title")!!)
positiveButton(R.string.dialog_ok)
negativeButton(R.string.dialog_cancel)
input(
hint = requireArguments().getString("prompt"),
inputType = InputType.TYPE_CLASS_NUMBER,
maxLength = requireArguments().getInt("digits")
) { _: MaterialDialog?, text: CharSequence -> consumer!!.accept(text.toString().toInt()) }
contentNullable(requireArguments().getString("content"))
onShow {
displayKeyboard(getInputField())
}
setMessage(requireArguments().getString("content"))
setView(R.layout.dialog_generic_text_input)
}.input(
hint = requireArguments().getString("prompt"),
inputType = InputType.TYPE_CLASS_NUMBER,
maxLength = requireArguments().getInt("digits"),
displayKeyboard = true
) { _, text: CharSequence ->
consumer!!.accept(text.toString().toInt())
dismiss()
}

return show
}
}
46 changes: 40 additions & 6 deletions AnkiDroid/src/main/java/com/ichi2/utils/AlertDialogFacade.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.ichi2.utils

import android.content.DialogInterface
import android.content.DialogInterface.OnClickListener
import android.text.InputFilter
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
Expand Down Expand Up @@ -202,30 +203,63 @@ fun AlertDialog.Builder.customListAdapter(adapter: RecyclerView.Adapter<*>) {
}

/**
* @param hint The hint text to be displayed to the user
* @param prefill The text to initially appear in the [EditText]
* @param allowEmpty If true, [DialogInterface.BUTTON_POSITIVE] is disabled if the [EditText] is empty
* @param displayKeyboard Whether to open the keyboard when the dialog appears
* @param callback called whenever the text is changed
* @param callback if [waitForPositiveButton], called when [positiveButton] is pressed, otherwise
* called whenever the text is changed
* @param maxLength if set, the user may not enter more than the supplied number of digits
* @param inputType see [EditText.setInputType]
* @param waitForPositiveButton MaterialDialog compat: if `false` [callback] is called on input
* if `true` [callback] is called when [positiveButton] is pressed
*/
fun AlertDialog.input(
hint: String? = null,
inputType: Int? = null,
prefill: CharSequence? = null,
allowEmpty: Boolean = false,
maxLength: Int? = null,
displayKeyboard: Boolean = false,
waitForPositiveButton: Boolean = true,
callback: (AlertDialog, CharSequence) -> Unit
): AlertDialog {
// Builder.setView() may not be called before show()
if (!this.isShowing) throw IllegalStateException("input() requires .show()")

getInputTextLayout().hint = hint

getInputField().apply {
if (displayKeyboard) {
AndroidUiUtils.setFocusAndOpenKeyboard(this, window!!)
}

doOnTextChanged { text, _, _, _ ->
callback(this@input, text ?: "")
// called after the callback so allowEmpty takes priority
if (!allowEmpty && text.isNullOrEmpty()) {
this@input.positiveButton.isEnabled = false
inputType?.let { this.inputType = it }

if (!waitForPositiveButton) {
doOnTextChanged { text, _, _, _ ->
callback(this@input, text ?: "")
}
} else {
positiveButton.setOnClickListener { callback(this@input, this.text.toString()) }
}

if (!allowEmpty) {
// this is called after callback() so allowEmpty takes priority
doOnTextChanged { text, _, _, _ ->
if (waitForPositiveButton) {
// this is the only validation filter we apply - toggle on or off
this@input.positiveButton.isEnabled = !text.isNullOrEmpty()
} else if (text.isNullOrEmpty()) {
// potentially other filters in `waitForPositiveButton`.
// WARN: this could be buggy as it does not toggle the button back on
this@input.positiveButton.isEnabled = false
}
}
}

maxLength?.let { filters += InputFilter.LengthFilter(it) }

requestFocus()
// this calls callback(this, prefill). positiveButton may be disabled if there's no prefill
setText(prefill)
Expand Down
21 changes: 0 additions & 21 deletions AnkiDroid/src/main/java/com/ichi2/utils/MaterialBuilderUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@

package com.ichi2.utils

import android.widget.EditText
import androidx.annotation.DrawableRes
import com.afollestad.materialdialogs.MaterialDialog
import com.ichi2.themes.Themes

// Extension methods for MaterialDialog workarounds in Kotlin
// Previously the methods accepted null into a non-null parameter,
Expand All @@ -29,21 +26,3 @@ fun MaterialDialog.contentNullable(message: CharSequence?): MaterialDialog {
message?.let { this.message(text = it) }
return this
}

/**
* Method to display keyboard when dialog is shown.
*
* @param editText EditText present in the dialog.
*/
fun MaterialDialog.displayKeyboard(editText: EditText) {
AndroidUiUtils.setFocusAndOpenKeyboard(editText, window!!)
}

/**
* Shows an icon to the left of the dialog title.
*/
fun MaterialDialog.iconAttr(
@DrawableRes res: Int
): MaterialDialog = apply {
this.icon(Themes.getResFromAttr(this.context, res))
}

0 comments on commit b0b2d52

Please sign in to comment.