From 26a9aa5d558e0e5d9dca16f3464338b97ecc4a7c Mon Sep 17 00:00:00 2001 From: PrathamDevX Date: Sat, 28 Feb 2026 00:24:11 +0530 Subject: [PATCH] feat(tags): show error and disable OK for duplicate tags --- .../com/ichi2/anki/dialogs/tags/TagsDialog.kt | 43 +++++++++++++++++++ AnkiDroid/src/main/res/values/02-strings.xml | 1 + 2 files changed, 44 insertions(+) diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/tags/TagsDialog.kt b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/tags/TagsDialog.kt index 1891cdf07e15..0af4163f658f 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/tags/TagsDialog.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/tags/TagsDialog.kt @@ -22,6 +22,7 @@ import androidx.core.content.ContextCompat import androidx.core.os.BundleCompat import androidx.core.os.bundleOf import androidx.core.view.isVisible +import androidx.core.widget.doAfterTextChanged import androidx.fragment.app.viewModels import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope @@ -372,6 +373,8 @@ class TagsDialog : AnalyticsDialogFragment { * @param prefixTag: The tag to be prefilled into the EditText section. A trailing '::' will be appended. */ @NeedsTest("The prefixTag should be prefilled properly") + @NeedsTest("Entering an existing tag should show an error and disable the OK button") + @NeedsTest("Entering a new valid tag should clear the error and enable the OK button") private fun createAddTagDialog(prefixTag: String?) { val addTagDialog = AlertDialog @@ -396,6 +399,46 @@ class TagsDialog : AnalyticsDialogFragment { inputET.setText("$prefixTag ") } inputET.moveCursorToEnd() + val positiveButton = + addTagDialog.getButton(AlertDialog.BUTTON_POSITIVE) + + positiveButton.isEnabled = false + + val textInputLayout = + inputET.parent?.parent + as? com.google.android.material.textfield.TextInputLayout + + inputET.doAfterTextChanged { text -> + + val rawTag = text?.toString()?.trim() + + if (rawTag.isNullOrEmpty()) { + textInputLayout?.error = null + positiveButton.isEnabled = false + return@doAfterTextChanged + } + + lifecycleScope.launch { + val tags = viewModel.tags.await() + + val normalized = + TagsUtil.getUniformedTag(rawTag) + + val exists = + tags.contains(normalized) + + if (exists) { + textInputLayout?.error = + getString(R.string.tag_already_exists) + + positiveButton.isEnabled = false + } else { + textInputLayout?.error = null + + positiveButton.isEnabled = true + } + } + } addTagDialog.show() } diff --git a/AnkiDroid/src/main/res/values/02-strings.xml b/AnkiDroid/src/main/res/values/02-strings.xml index 8c8882821128..5f6a13d1506f 100644 --- a/AnkiDroid/src/main/res/values/02-strings.xml +++ b/AnkiDroid/src/main/res/values/02-strings.xml @@ -190,6 +190,7 @@ This is a special deck for studying outside of the normal schedule. Cards will be automatically returned to their original decks after you review them. Deleting this deck from the deck list will return all remaining cards to their original deck. Touch “%2$s” to confirm adding “%1$s” Existing tag “%1$s” selected + Tag already exists