diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/pages/CongratsPage.kt b/AnkiDroid/src/main/java/com/ichi2/anki/pages/CongratsPage.kt
index 5349e471a72e..0e1bf95b3945 100644
--- a/AnkiDroid/src/main/java/com/ichi2/anki/pages/CongratsPage.kt
+++ b/AnkiDroid/src/main/java/com/ichi2/anki/pages/CongratsPage.kt
@@ -15,7 +15,6 @@
*/
package com.ichi2.anki.pages
-import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
@@ -23,6 +22,7 @@ import android.view.View
import android.webkit.JavascriptInterface
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
+import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.flowWithLifecycle
@@ -30,6 +30,7 @@ import androidx.lifecycle.lifecycleScope
import anki.collection.OpChanges
import com.google.android.material.appbar.MaterialToolbar
import com.ichi2.anki.CollectionManager
+import com.ichi2.anki.CollectionManager.TR
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.DeckPicker
import com.ichi2.anki.FilteredDeckOptions
@@ -40,9 +41,13 @@ import com.ichi2.anki.SingleFragmentActivity
import com.ichi2.anki.StudyOptionsActivity
import com.ichi2.anki.dialogs.customstudy.CustomStudyDialog
import com.ichi2.anki.launchCatchingIO
+import com.ichi2.anki.launchCatchingTask
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.showThemedToast
import com.ichi2.anki.snackbar.showSnackbar
+import com.ichi2.anki.utils.SECONDS_PER_DAY
+import com.ichi2.anki.utils.TIME_HOUR
+import com.ichi2.anki.utils.TIME_MINUTE
import com.ichi2.libanki.ChangeManager
import com.ichi2.libanki.DeckId
import com.ichi2.libanki.undoableOp
@@ -50,6 +55,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
+import kotlin.math.round
class CongratsPage :
PageFragment(),
@@ -183,15 +189,18 @@ class CongratsPage :
private fun displayNewCongratsScreen(context: Context): Boolean =
context.sharedPrefs().getBoolean("new_congrats_screen", false)
- fun display(activity: Activity) {
+ fun display(activity: FragmentActivity) {
if (displayNewCongratsScreen(activity)) {
activity.startActivity(getIntent(activity))
} else {
- showThemedToast(activity, R.string.studyoptions_congrats_finished, false)
+ activity.launchCatchingTask {
+ val message = getDeckFinishedMessage(activity)
+ showThemedToast(activity, message, false)
+ }
}
}
- fun onReviewsCompleted(activity: Activity, cardsInDeck: Boolean) {
+ fun onReviewsCompleted(activity: FragmentActivity, cardsInDeck: Boolean) {
if (displayNewCongratsScreen(activity)) {
activity.startActivity(getIntent(activity))
return
@@ -199,12 +208,35 @@ class CongratsPage :
// Show a message when reviewing has finished
if (cardsInDeck) {
- activity.showSnackbar(R.string.studyoptions_congrats_finished)
+ activity.launchCatchingTask {
+ val message = getDeckFinishedMessage(activity)
+ activity.showSnackbar(message)
+ }
} else {
activity.showSnackbar(R.string.studyoptions_no_cards_due)
}
}
+ // based in https://github.com/ankitects/anki/blob/9b4dd54312de8798a3f2bee07892bb3a488d1f9b/ts/routes/congrats/lib.ts#L8C17-L8C34
+ private suspend fun getDeckFinishedMessage(activity: FragmentActivity): String {
+ val info = withCol { sched.congratulationsInfo() }
+ val secsUntilNextLearn = info.secsUntilNextLearn
+ if (secsUntilNextLearn >= SECONDS_PER_DAY) {
+ return activity.getString(R.string.studyoptions_congrats_finished)
+ }
+ // https://github.com/ankitects/anki/blob/9b4dd54312de8798a3f2bee07892bb3a488d1f9b/ts/lib/tslib/time.ts#L22
+ val (unit, amount) = if (secsUntilNextLearn < TIME_MINUTE) {
+ "seconds" to secsUntilNextLearn.toDouble()
+ } else if (secsUntilNextLearn < TIME_HOUR) {
+ "minutes" to secsUntilNextLearn / TIME_MINUTE
+ } else {
+ "hours" to secsUntilNextLearn / TIME_HOUR
+ }
+
+ val nextLearnDue = TR.schedulingNextLearnDue(unit, round(amount).toInt())
+ return activity.getString(R.string.studyoptions_congrats_next_due_in, nextLearnDue)
+ }
+
fun DeckPicker.onDeckCompleted() {
startActivity(getIntent(this))
}
diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/utils/Time.kt b/AnkiDroid/src/main/java/com/ichi2/anki/utils/Time.kt
index 819b751fdc0a..0483df1e3d78 100644
--- a/AnkiDroid/src/main/java/com/ichi2/anki/utils/Time.kt
+++ b/AnkiDroid/src/main/java/com/ichi2/anki/utils/Time.kt
@@ -37,9 +37,9 @@ private const val TIME_DAY_LONG = 24 * TIME_HOUR_LONG
// These are doubles on purpose because we want a rounded, not integer result later.
// Use values from Anki Desktop:
// https://github.com/ankitects/anki/blob/05cc47a5d3d48851267cda47f62af79f468eb028/rslib/src/sched/timespan.rs#L83
-private const val TIME_MINUTE = 60.0 // seconds
-private const val TIME_HOUR = 60.0 * TIME_MINUTE
-private const val TIME_DAY = 24.0 * TIME_HOUR
+const val TIME_MINUTE = 60.0 // seconds
+const val TIME_HOUR = 60.0 * TIME_MINUTE
+const val TIME_DAY = 24.0 * TIME_HOUR
private const val TIME_MONTH = 30.0 * TIME_DAY
private const val TIME_YEAR = 12.0 * TIME_MONTH
diff --git a/AnkiDroid/src/main/res/values/01-core.xml b/AnkiDroid/src/main/res/values/01-core.xml
index 414a22872a0a..5b7347225a5c 100644
--- a/AnkiDroid/src/main/res/values/01-core.xml
+++ b/AnkiDroid/src/main/res/values/01-core.xml
@@ -111,6 +111,7 @@
Deck Search
Invalid deck name
Congratulations! You have finished for now.
+ Congratulations! %s
No cards are due yet
Device storage not mounted