Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import android.app.Dialog
import android.content.res.Resources
import android.os.Bundle
import android.os.Parcelable
import android.text.InputFilter
import android.text.Spanned
import android.util.TypedValue
import android.view.WindowManager
import android.view.inputmethod.EditorInfo
Expand Down Expand Up @@ -88,6 +90,7 @@ import com.ichi2.utils.setPaddingRelative
import com.ichi2.utils.textAsIntOrNull
import com.ichi2.utils.title
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.parcelize.Parcelize
import net.ankiweb.rsdroid.BackendException
Expand Down Expand Up @@ -335,10 +338,18 @@ class CustomStudyDialog : AnalyticsDialogFragment() {
if (contextMenuOption == EXTEND_NEW || contextMenuOption == EXTEND_REV) {
inputType = EditorInfo.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_FLAG_SIGNED
}
if (contextMenuOption == STUDY_FORGOT) {
filters = arrayOf(InputFilter.LengthFilter(9), NoLeadingZeroFilter())
val initialValue = defaultValue.toIntOrNull() ?: 1
binding.detailsEditText2Layout.suffixText = resources.getQuantityString(R.plurals.set_due_date_label_suffix, initialValue)
}
}

val positiveBtnLabel =
if (contextMenuOption == STUDY_TAGS) {
TR.customStudyChooseTags().toSentenceCase(R.string.sentence_choose_tags)
} else if (contextMenuOption == STUDY_FORGOT) {
getString(R.string.dialog_positive_create)
} else {
getString(R.string.dialog_ok)
}
Expand Down Expand Up @@ -421,8 +432,41 @@ class CustomStudyDialog : AnalyticsDialogFragment() {
}
}

binding.detailsEditText2.doAfterTextChanged {
binding.detailsEditText2.doAfterTextChanged { text ->
dialog.positiveButton.isEnabled = userInputValue != null && userInputValue != 0
val value = text?.toString()?.toIntOrNull()

if (contextMenuOption == STUDY_FORGOT) {
if (userInputValue == null) {
dialog.positiveButton.isEnabled = false
binding.detailsEditText2Layout.error = getString(R.string.invalid_value)
return@doAfterTextChanged
}
if (userInputValue == 0) {
binding.detailsEditText2Layout.error = getString(R.string.custom_study_ahead_prevent_leading_zeros)
dialog.positiveButton.isEnabled = false
return@doAfterTextChanged
}

val storedValue = value ?: return@doAfterTextChanged
binding.detailsEditText2Layout.suffixText = resources.getQuantityString(R.plurals.set_due_date_label_suffix, storedValue)

val currentValue = userInputValue

lifecycleScope.launch {
val hasCards = hasMatchingCards(contextMenuOption, userInputValue)

if (currentValue != userInputValue) return@launch

if (hasCards) {
binding.detailsEditText2Layout.error = null
dialog.positiveButton.isEnabled = true
} else {
binding.detailsEditText2Layout.error = getString(R.string.no_cards_matched_criteria)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use TR.customStudyNoCardsMatchedTheCriteriaYou instead of the string resource here to avoid duplication

dialog.positiveButton.isEnabled = false
}
}
}
}

// Show soft keyboard
Expand Down Expand Up @@ -484,6 +528,29 @@ class CustomStudyDialog : AnalyticsDialogFragment() {
}
}

private suspend fun hasMatchingCards(
option: ContextMenuOption,
input: Int?,
): Boolean {
if (option != STUDY_FORGOT) return true

val value = input ?: return false
if (value <= 0) return false

return try {
withCol {
val currentDeckName = decks.name(viewModel.deckId)

val hasForgottenCards =
findCards("deck:\"$currentDeckName\" rated:$value:1").isNotEmpty()
hasForgottenCards
}
} catch (e: Exception) {
Timber.e(e)
true
}
}

/**
* Loads [CustomStudyDefaults] from the backend
*
Expand All @@ -508,7 +575,7 @@ class CustomStudyDialog : AnalyticsDialogFragment() {
when (selectedSubDialog) {
EXTEND_NEW -> deferredDefaults.getCompleted().labelForNewQueueAvailable()
EXTEND_REV -> deferredDefaults.getCompleted().labelForReviewQueueAvailable()
STUDY_FORGOT,
STUDY_FORGOT -> TR.customStudyReviewForgottenCards()
STUDY_AHEAD,
STUDY_PREVIEW,
STUDY_TAGS,
Expand Down Expand Up @@ -564,6 +631,25 @@ class CustomStudyDialog : AnalyticsDialogFragment() {
* Represents actions for managing custom study sessions and extending study limits.
* These actions are passed between fragments and activities via the FragmentResult API.
*/
class NoLeadingZeroFilter : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int,
): CharSequence? {
val newText = dest?.replaceRange(dstart, dend, source?.subSequence(start, end) ?: "")

return if (newText != null && newText.length > 1 && newText.startsWith("0")) {
""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here as well : see this comment #20618 (comment)

} else {
null
}
}
}

enum class CustomStudyAction {
EXTEND_STUDY_LIMITS,
CUSTOM_STUDY_SESSION,
Expand Down
9 changes: 5 additions & 4 deletions AnkiDroid/src/main/res/layout/fragment_custom_study.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
android:layout_marginRight="4dip"
android:gravity="start"
android:text=""
android:textSize="16sp" />
android:textSize="18sp"
android:textStyle="bold"/>

<com.ichi2.ui.FixedTextView
android:id="@+id/details_text_2"
Expand All @@ -55,13 +56,13 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/details_edit_text_2_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:suffixTextAppearance="@style/TextAppearance.MaterialComponents.Body1">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/details_edit_text_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:inputType="number|numberSigned"
tools:text="1"
/>
Expand All @@ -88,4 +89,4 @@
tools:text="New cards only"
/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</LinearLayout>
1 change: 1 addition & 0 deletions AnkiDroid/src/main/res/values/02-strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -458,5 +458,6 @@ opening the system text to speech settings fails">Failed to open text to speech
<!-- Other errors -->
<!-- Similar to TR.qtMiscNameExists(): "Name exists." -->
<string name="error_name_exists">Name already exists</string>
<string name="no_cards_matched_criteria">No cards matched the criteria</string>
</resources>

3 changes: 2 additions & 1 deletion AnkiDroid/src/main/res/values/03-dialogs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@
<string name="intent_aedict_category">To add cards to AnkiDroid remove all Notepad categories or add one named “default”</string>
<string name="custom_study_new_extend">Increase/decrease (“-3”) today’s new card limit by</string>
<string name="custom_study_rev_extend">Increase/decrease (“-3”) today’s review limit by</string>
<string name="custom_study_forgotten">Review cards forgotten in last x days:</string>
<string name="custom_study_forgotten">Review cards forgotten in last:</string>
<string name="custom_study_ahead">Review ahead by x days:</string>
<string name="custom_study_ahead_prevent_leading_zeros">Value must be greater than 0</string>
<string name="custom_study_preview">Preview new cards added in the last x days:</string>
<string name="custom_study_tags">Select x cards from the deck:</string>

Expand Down
Loading