Skip to content

Commit

Permalink
NF: improve typing of MediaCheckDialog
Browse files Browse the repository at this point in the history
  • Loading branch information
Arthur-Milchior committed Dec 4, 2024
1 parent 114ef10 commit 0560c51
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 66 deletions.
10 changes: 5 additions & 5 deletions AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,7 @@ open class DeckPicker :
}
R.id.action_check_media -> {
Timber.i("DeckPicker:: Check media button pressed")
showMediaCheckDialog(MediaCheckDialog.DIALOG_CONFIRM_MEDIA_CHECK)
showMediaCheckDialog(MediaCheckDialog.Type.DIALOG_CONFIRM_MEDIA_CHECK)
return true
}
R.id.action_empty_cards -> {
Expand Down Expand Up @@ -1414,7 +1414,7 @@ open class DeckPicker :
}
KeyEvent.KEYCODE_M -> {
Timber.i("Check media from keypress")
showMediaCheckDialog(MediaCheckDialog.DIALOG_CONFIRM_MEDIA_CHECK)
showMediaCheckDialog(MediaCheckDialog.Type.DIALOG_CONFIRM_MEDIA_CHECK)
return true
}
KeyEvent.KEYCODE_E -> {
Expand Down Expand Up @@ -1719,11 +1719,11 @@ open class DeckPicker :
}
}

override fun showMediaCheckDialog(dialogType: Int) {
override fun showMediaCheckDialog(dialogType: MediaCheckDialog.Type) {
showAsyncDialogFragment(MediaCheckDialog.newInstance(dialogType))
}

override fun showMediaCheckDialog(dialogType: Int, checkList: MediaCheckResult) {
override fun showMediaCheckDialog(dialogType: MediaCheckDialog.Type, checkList: MediaCheckResult) {
showAsyncDialogFragment(MediaCheckDialog.newInstance(dialogType, checkList))
}

Expand Down Expand Up @@ -1805,7 +1805,7 @@ open class DeckPicker :
override fun mediaCheck() {
launchCatchingTask {
val mediaCheckResult = checkMedia()
showMediaCheckDialog(MediaCheckDialog.DIALOG_MEDIA_CHECK_RESULTS, mediaCheckResult)
showMediaCheckDialog(MediaCheckDialog.Type.DIALOG_MEDIA_CHECK_RESULTS, mediaCheckResult)
}
}

Expand Down
144 changes: 84 additions & 60 deletions AnkiDroid/src/main/java/com/ichi2/anki/dialogs/MediaCheckDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,38 @@ import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AlertDialog
import androidx.core.os.bundleOf
import com.ichi2.anki.AnkiActivity
import com.ichi2.anki.DeckPicker
import com.ichi2.anki.R
import com.ichi2.anki.dialogs.MediaCheckDialog.Type.Companion.toType
import com.ichi2.anki.showError
import com.ichi2.libanki.MediaCheckResult

/**
* Key for an ordinal in the Type.entries.
*/
const val MEDIA_CHECK_DIALOG_TYPE_KEY = "dialogType"

/**
* Key for an array of strings of name of missing media
*/
const val NO_HAVE = "noHave"

/**
* Key for an array of strings of name of unused media
*/
const val UNUSED = "unused"

/**
* Key for an array of strings of name of invalid media
*/
const val INVALID = "invalid"
class MediaCheckDialog : AsyncDialogFragment() {
interface MediaCheckDialogListener {
fun showMediaCheckDialog(dialogType: Int)
fun showMediaCheckDialog(dialogType: Int, checkList: MediaCheckResult)
fun showMediaCheckDialog(dialogType: Type)
fun showMediaCheckDialog(dialogType: Type, checkList: MediaCheckResult)
fun mediaCheck()
fun deleteUnused(unused: List<String>)
fun dismissAllDialogFragments()
Expand All @@ -32,8 +51,8 @@ class MediaCheckDialog : AsyncDialogFragment() {
super.onCreate(savedInstanceState)
val dialog = AlertDialog.Builder(requireContext())
.setTitle(notificationTitle)
return when (requireArguments().getInt("dialogType")) {
DIALOG_CONFIRM_MEDIA_CHECK -> {
return when (typeFromArguments()) {
Type.DIALOG_CONFIRM_MEDIA_CHECK -> {
dialog.setMessage(notificationMessage)
.setPositiveButton(R.string.dialog_ok) { _, _ ->
(activity as MediaCheckDialogListener?)?.mediaCheck()
Expand All @@ -44,10 +63,10 @@ class MediaCheckDialog : AsyncDialogFragment() {
}
.create()
}
DIALOG_MEDIA_CHECK_RESULTS -> {
val nohave = requireArguments().getStringArrayList("nohave")
val unused = requireArguments().getStringArrayList("unused")
val invalid = requireArguments().getStringArrayList("invalid")
Type.DIALOG_MEDIA_CHECK_RESULTS -> {
val noHave = requireArguments().getStringArrayList(NO_HAVE)
val unused = requireArguments().getStringArrayList(UNUSED)
val invalid = requireArguments().getStringArrayList(INVALID)
// Generate report
val report = StringBuilder()
if (invalid!!.isNotEmpty()) {
Expand All @@ -59,11 +78,11 @@ class MediaCheckDialog : AsyncDialogFragment() {
}
report.append(String.format(res().getString(R.string.check_media_unused), unused.size))
}
if (nohave!!.isNotEmpty()) {
if (noHave!!.isNotEmpty()) {
if (report.isNotEmpty()) {
report.append("\n")
}
report.append(String.format(res().getString(R.string.check_media_nohave), nohave.size))
report.append(String.format(res().getString(R.string.check_media_nohave), noHave.size))
}
if (report.isEmpty()) {
report.append(res().getString(R.string.check_media_no_unused_missing))
Expand Down Expand Up @@ -103,7 +122,6 @@ class MediaCheckDialog : AsyncDialogFragment() {
.setCancelable(false)
.create()
}
else -> null!!
}
}

Expand All @@ -112,105 +130,111 @@ class MediaCheckDialog : AsyncDialogFragment() {
}

override val notificationMessage: String
get() {
return when (requireArguments().getInt("dialogType")) {
DIALOG_CONFIRM_MEDIA_CHECK -> res().getString(R.string.check_media_warning)
DIALOG_MEDIA_CHECK_RESULTS -> res().getString(R.string.check_media_acknowledge)
else -> res().getString(R.string.app_name)
}
get() = when (typeFromArguments()) {
Type.DIALOG_CONFIRM_MEDIA_CHECK -> res().getString(R.string.check_media_warning)
Type.DIALOG_MEDIA_CHECK_RESULTS -> res().getString(R.string.check_media_acknowledge)
}

override val notificationTitle: String
get() {
return if (requireArguments().getInt("dialogType") == DIALOG_CONFIRM_MEDIA_CHECK) {
get() = when (typeFromArguments()) {
Type.DIALOG_CONFIRM_MEDIA_CHECK -> {
res().getString(R.string.check_media_title)
} else {
}

Type.DIALOG_MEDIA_CHECK_RESULTS -> {
res().getString(R.string.app_name)
}
}

private fun typeFromArguments() = requireArguments().getInt(MEDIA_CHECK_DIALOG_TYPE_KEY).toType()

override val dialogHandlerMessage: MediaCheckCompleteDialog
get() {
val dialogType = requireArguments().getInt("dialogType")
val nohave = requireArguments().getStringArrayList("nohave")
val unused = requireArguments().getStringArrayList("unused")
val invalid = requireArguments().getStringArrayList("invalid")
val dialogType = typeFromArguments()
val noHave = requireArguments().getStringArrayList(NO_HAVE)
val unused = requireArguments().getStringArrayList(UNUSED)
val invalid = requireArguments().getStringArrayList(INVALID)

return MediaCheckCompleteDialog(dialogType, nohave, unused, invalid)
return MediaCheckCompleteDialog(dialogType, noHave, unused, invalid)
}

companion object {
const val DIALOG_CONFIRM_MEDIA_CHECK = 0
const val DIALOG_MEDIA_CHECK_RESULTS = 1
enum class Type(val code: Int) {
DIALOG_CONFIRM_MEDIA_CHECK(0),
DIALOG_MEDIA_CHECK_RESULTS(1);

@VisibleForTesting
val dialogTypes = arrayOf(DIALOG_CONFIRM_MEDIA_CHECK, DIALOG_MEDIA_CHECK_RESULTS)
companion object {
fun Int.toType() = Type.entries.first { this == it.code }
}
}

companion object {
@CheckResult
fun newInstance(dialogType: Int): MediaCheckDialog {
fun newInstance(dialogType: Type): MediaCheckDialog {
val f = MediaCheckDialog()
val args = Bundle()
args.putInt("dialogType", dialogType)
args.putInt(MEDIA_CHECK_DIALOG_TYPE_KEY, dialogType.code)
f.arguments = args
return f
}

// TODO Instead of putting string arrays into the bundle,
// make MediaCheckResult parcelable with @Parcelize and put it instead.
// TODO Extract keys to constants
fun newInstance(dialogType: Int, checkList: MediaCheckResult): MediaCheckDialog {
fun newInstance(dialogType: Type, checkList: MediaCheckResult): MediaCheckDialog {
val f = MediaCheckDialog()
val args = Bundle()
args.putStringArrayList("nohave", ArrayList(checkList.missingFileNames))
args.putStringArrayList("unused", ArrayList(checkList.unusedFileNames))
args.putStringArrayList("invalid", ArrayList(checkList.invalidFileNames))
args.putInt("dialogType", dialogType)
args.putStringArrayList(NO_HAVE, ArrayList(checkList.missingFileNames))
args.putStringArrayList(UNUSED, ArrayList(checkList.unusedFileNames))
args.putStringArrayList(INVALID, ArrayList(checkList.invalidFileNames))
args.putInt(MEDIA_CHECK_DIALOG_TYPE_KEY, dialogType.code)
f.arguments = args
return f
}
}

class MediaCheckCompleteDialog(
private val dialogType: Int,
private val dialogType: Type,
private val noHave: ArrayList<String>?,
private val unused: ArrayList<String>?,
private val invalid: ArrayList<String>?
) : DialogHandlerMessage(WhichDialogHandler.MSG_SHOW_MEDIA_CHECK_COMPLETE_DIALOG, "MediaCheckCompleteDialog") {
override fun handleAsyncMessage(activity: AnkiActivity) {
// Media check results
val id = dialogType
if (id != DIALOG_CONFIRM_MEDIA_CHECK) {
// we may be called via any AnkiActivity but media check is a DeckPicker thing
if (activity !is DeckPicker) {
showError(
activity,
activity.getString(R.string.something_wrong),
ClassCastException(activity.javaClass.simpleName + " is not " + DeckPicker.javaClass.simpleName),
true
)
return
when (dialogType) {
Type.DIALOG_MEDIA_CHECK_RESULTS -> {
// we may be called via any AnkiActivity but media check is a DeckPicker thing
if (activity !is DeckPicker) {
showError(
activity,
activity.getString(R.string.something_wrong),
ClassCastException(activity.javaClass.simpleName + " is not " + DeckPicker.javaClass.simpleName),
true
)
return
}
val checkList = MediaCheckResult(noHave ?: arrayListOf(), unused ?: arrayListOf(), invalid ?: arrayListOf())
activity.showMediaCheckDialog(dialogType, checkList)
}
val checkList = MediaCheckResult(noHave ?: arrayListOf(), unused ?: arrayListOf(), invalid ?: arrayListOf())
activity.showMediaCheckDialog(id, checkList)
Type.DIALOG_CONFIRM_MEDIA_CHECK -> { }
}
}

override fun toMessage(): Message = Message.obtain().apply {
what = this@MediaCheckCompleteDialog.what
data = bundleOf(
"nohave" to noHave,
"unused" to unused,
"invalid" to invalid,
"dialogType" to dialogType
NO_HAVE to noHave,
UNUSED to unused,
INVALID to invalid,
MEDIA_CHECK_DIALOG_TYPE_KEY to dialogType
)
}

companion object {
fun fromMessage(message: Message): MediaCheckCompleteDialog {
val dialogType = message.data.getInt("dialogType")
val noHave = message.data.getStringArrayList("noHave")
val unused = message.data.getStringArrayList("unused")
val invalid = message.data.getStringArrayList("invalid")
val dialogType = message.data.getInt(MEDIA_CHECK_DIALOG_TYPE_KEY).toType()
val noHave = message.data.getStringArrayList(NO_HAVE)
val unused = message.data.getStringArrayList(UNUSED)
val invalid = message.data.getStringArrayList(INVALID)
return MediaCheckCompleteDialog(dialogType, noHave, unused, invalid)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class AsyncDialogFragmentsTest {

@Test
fun `MediaCheckDialog does not require context`() {
for (dialogType in MediaCheckDialog.dialogTypes) {
for (dialogType in MediaCheckDialog.Type.entries) {
val instance = MediaCheckDialog.newInstance(dialogType)
assertDoesNotThrow("$dialogType message required a context") { instance.notificationMessage }
assertDoesNotThrow("$dialogType title required a context") { instance.notificationTitle }
Expand Down

0 comments on commit 0560c51

Please sign in to comment.