Skip to content

Commit

Permalink
Refactored : CustomStudyDialog to uses AlertDialog
Browse files Browse the repository at this point in the history
Refactor : CustomStudy DialogTest to support AlertDialog
  • Loading branch information
neeldoshii committed Apr 4, 2024
1 parent bb0c4a8 commit b48180b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,9 @@ import android.widget.EditText
import android.widget.TextView
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AlertDialog
import androidx.core.content.edit
import androidx.fragment.app.DialogFragment
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.WhichButton
import com.afollestad.materialdialogs.actions.getActionButton
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.list.listItems
import com.ichi2.anki.*
import com.ichi2.anki.UIUtils.showThemedToast
import com.ichi2.anki.analytics.AnalyticsDialogFragment
Expand All @@ -53,6 +49,12 @@ import com.ichi2.libanki.Deck
import com.ichi2.libanki.DeckId
import com.ichi2.utils.HashUtil.hashMapInit
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.cancelable
import com.ichi2.utils.customView
import com.ichi2.utils.listItems
import com.ichi2.utils.negativeButton
import com.ichi2.utils.positiveButton
import com.ichi2.utils.title
import net.ankiweb.rsdroid.exceptions.BackendDeckIsFilteredException
import org.json.JSONArray
import org.json.JSONObject
Expand Down Expand Up @@ -100,15 +102,16 @@ class CustomStudyDialog(private val collection: Collection, private val customSt
* Build a context menu for custom study
* @param id the id type of the dialog
*/
private fun buildContextMenu(id: Int): MaterialDialog {
private fun buildContextMenu(id: Int): AlertDialog {
val listIds = getListIds(ContextMenuConfiguration.fromInt(id)).map { it.value }.toIntArray()
val jumpToReviewer = requireArguments().getBoolean("jumpToReviewer")
val items = getValuesFromKeys(keyValueMap, listIds).toList().map { it as CharSequence }

return MaterialDialog(requireActivity())
return AlertDialog.Builder(requireActivity())
.title(R.string.custom_study)
.cancelable(true)
.listItems(items = getValuesFromKeys(keyValueMap, listIds).toList().map { it as CharSequence }) { _: MaterialDialog, _: Int, charSequence: CharSequence ->
when (ContextMenuOption.fromString(resources, charSequence.toString())) {
.listItems(items = items) { _, index ->
when (ContextMenuOption.fromString(resources, items[index].toString())) {
DECK_OPTIONS -> {
// User asked to permanently change the deck options
val deckId = requireArguments().getLong("did")
Expand Down Expand Up @@ -144,14 +147,14 @@ class CustomStudyDialog(private val collection: Collection, private val customSt
// User asked for a standard custom study option
val d = CustomStudyDialog(collection, customStudyListener)
.withArguments(
ContextMenuOption.fromString(resources, charSequence.toString()),
ContextMenuOption.fromString(resources, items[index].toString()),
requireArguments().getLong("did"),
jumpToReviewer
)
customStudyListener?.showDialogFragment(d)
}
}
}
}.create()
}

@KotlinCleanup("make this use enum instead of Int")
Expand All @@ -167,7 +170,7 @@ class CustomStudyDialog(private val collection: Collection, private val customSt
* Build an input dialog that is used to get a parameter related to custom study from the user
* @param contextMenuOption the option of the dialog
*/
private fun buildInputDialog(contextMenuOption: ContextMenuOption): MaterialDialog {
private fun buildInputDialog(contextMenuOption: ContextMenuOption): AlertDialog {
/*
TODO: Try to change to a standard input dialog (currently the thing holding us back is having the extra
TODO: hint line for the number of cards available, and having the pre-filled text selected by default)
Expand All @@ -194,8 +197,8 @@ class CustomStudyDialog(private val collection: Collection, private val customSt
// Whether or not to jump straight to the reviewer
val jumpToReviewer = requireArguments().getBoolean("jumpToReviewer")
// Set material dialog parameters
val dialog = MaterialDialog(requireActivity())
.customView(view = v, scrollable = true, noVerticalPadding = false, horizontalPadding = true)
val dialog = AlertDialog.Builder(requireActivity())
.customView(view = v, paddingLeft = 64, paddingRight = 64, paddingTop = 32, paddingBottom = 32)
.positiveButton(R.string.dialog_ok) {
// Get the value selected by user
val n: Int = try {
Expand Down Expand Up @@ -277,16 +280,17 @@ class CustomStudyDialog(private val collection: Collection, private val customSt
.negativeButton(R.string.dialog_cancel) {
customStudyListener?.dismissAllDialogFragments()
}
.create() // Added .create() because we wanted to access alertDialog positive button enable state
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
try {
editText.text.toString().toInt()
dialog.getActionButton(WhichButton.POSITIVE).isEnabled = true
dialog.positiveButton.isEnabled = true
} catch (e: Exception) {
Timber.w(e)
dialog.getActionButton(WhichButton.POSITIVE).isEnabled = false
dialog.positiveButton.isEnabled = false
}
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,22 @@
*/
package com.ichi2.anki.dialogs

import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.testing.FragmentScenario
import androidx.lifecycle.Lifecycle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.WhichButton
import com.afollestad.materialdialogs.actions.getActionButton
import com.ichi2.anki.R
import com.ichi2.anki.RobolectricTest
import com.ichi2.anki.dialogs.customstudy.CustomStudyDialog
import com.ichi2.anki.dialogs.customstudy.CustomStudyDialog.CustomStudyListener
import com.ichi2.anki.dialogs.customstudy.CustomStudyDialogFactory
import com.ichi2.anki.dialogs.utils.performPositiveClick
import com.ichi2.libanki.Collection
import com.ichi2.libanki.sched.Scheduler
import com.ichi2.testutils.ParametersUtils
import com.ichi2.testutils.isJsonEqual
import com.ichi2.testutils.items
import com.ichi2.utils.KotlinCleanup
import org.hamcrest.CoreMatchers.notNullValue
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.hamcrest.core.IsNull
import org.json.JSONObject
import org.junit.After
Expand All @@ -44,6 +40,7 @@ import org.mockito.Mockito
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.robolectric.annotation.Config
import kotlin.test.assertNotNull

@RunWith(AndroidJUnit4::class)
class CustomStudyDialogTest : RobolectricTest() {
Expand All @@ -66,12 +63,11 @@ class CustomStudyDialogTest : RobolectricTest() {
.withArguments(CustomStudyDialog.ContextMenuOption.STUDY_AHEAD, 1)
.arguments
val factory = CustomStudyDialogFactory({ this.col }, mockListener)
val scenario = FragmentScenario.launch(CustomStudyDialog::class.java, args, factory)
scenario.moveToState(Lifecycle.State.STARTED)
val scenario = FragmentScenario.launch(CustomStudyDialog::class.java, args, androidx.appcompat.R.style.Theme_AppCompat, factory)
scenario.moveToState(Lifecycle.State.RESUMED)
scenario.onFragment { f: CustomStudyDialog ->
val dialog = f.dialog as MaterialDialog?
MatcherAssert.assertThat(dialog, IsNull.notNullValue())
dialog!!.getActionButton(WhichButton.POSITIVE).callOnClick()
val dialog = assertNotNull(f.dialog as AlertDialog?)
dialog.performPositiveClick()
}
val customStudy = col.decks.current()
MatcherAssert.assertThat("Custom Study should be dynamic", customStudy.isFiltered)
Expand Down Expand Up @@ -120,9 +116,8 @@ class CustomStudyDialogTest : RobolectricTest() {
val scenario = FragmentScenario.launch(CustomStudyDialog::class.java, args, androidx.appcompat.R.style.Theme_AppCompat, factory)
scenario.moveToState(Lifecycle.State.STARTED)
scenario.onFragment { f: CustomStudyDialog ->
val dialog = f.dialog as MaterialDialog?
val dialog = f.dialog as AlertDialog?
MatcherAssert.assertThat(dialog, IsNull.notNullValue())
MatcherAssert.assertThat(dialog!!.items, Matchers.not(Matchers.hasItem(getResourceString(R.string.custom_study_increase_new_limit))))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@

package com.ichi2.anki.dialogs.utils

import android.content.DialogInterface
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.test.platform.app.InstrumentationRegistry
import com.ichi2.utils.HandlerUtils.executeFunctionUsingHandler
import com.ichi2.utils.getInputField
import org.hamcrest.MatcherAssert.*
import kotlin.test.assertNotNull

var AlertDialog.input
get() = getInputField().text.toString()
Expand All @@ -28,3 +34,12 @@ val AlertDialog.title
get() = requireNotNull(this.findViewById<TextView>(androidx.appcompat.R.id.alertTitle)) {
"androidx.appcompat.R.id.alertTitle not found"
}.text.toString()

fun AlertDialog.performPositiveClick() {
// This exists as callOnClick did not call the listener
val positiveButton = assertNotNull(getButton(DialogInterface.BUTTON_POSITIVE), message = "positive button")
assertThat("button is visible", positiveButton.isVisible)
assertThat("button is enalbed", positiveButton.isEnabled)
executeFunctionUsingHandler { positiveButton.callOnClick() }
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
}

0 comments on commit b48180b

Please sign in to comment.