Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(card-template-editor): Add Restore to Default feature #17461

Merged
merged 1 commit into from
Dec 17, 2024
Merged
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
66 changes: 66 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateEditor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.ichi2.anki

import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.os.Handler
Expand Down Expand Up @@ -49,10 +50,14 @@ import androidx.fragment.app.commitNow
import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import anki.notetypes.StockNotetype
import anki.notetypes.StockNotetype.OriginalStockKind.ORIGINAL_STOCK_KIND_UNKNOWN_VALUE
import anki.notetypes.notetypeId
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.ichi2.anki.CollectionManager.TR
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.android.input.ShortcutGroup
import com.ichi2.anki.android.input.shortcut
Expand Down Expand Up @@ -83,12 +88,18 @@ import com.ichi2.libanki.NotetypeJson
import com.ichi2.libanki.Notetypes
import com.ichi2.libanki.Notetypes.Companion.NOT_FOUND_NOTE_TYPE
import com.ichi2.libanki.exception.ConfirmModSchemaException
import com.ichi2.libanki.getStockNotetype
import com.ichi2.libanki.getStockNotetypeKinds
import com.ichi2.libanki.restoreNotetypeToStock
import com.ichi2.libanki.undoableOp
import com.ichi2.themes.Themes
import com.ichi2.ui.FixedEditText
import com.ichi2.ui.FixedTextView
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.copyToClipboard
import com.ichi2.utils.jsonObjectIterable
import com.ichi2.utils.listItems
import com.ichi2.utils.show
import net.ankiweb.rsdroid.Translations
import org.json.JSONArray
import org.json.JSONException
Expand Down Expand Up @@ -842,6 +853,7 @@ open class CardTemplateEditor :
* Setups the part of the menu that can be used either in template editor or in previewer fragment.
*/
fun setupCommonMenu(menu: Menu) {
menu.findItem(R.id.action_restore_to_default).title = CollectionManager.TR.cardTemplatesRestoreToDefault()
if (noteTypeCreatesDynamicNumberOfNotes()) {
Timber.d("Editing cloze/occlusion model, disabling add/delete card template and deck override functionality")
menu.findItem(R.id.action_add).isVisible = false
Expand Down Expand Up @@ -874,11 +886,24 @@ open class CardTemplateEditor :
menu.findItem(R.id.action_insert_field).isVisible = isInsertFieldItemVisible
}

@NeedsTest("Notetype is restored to stock kind")
private suspend fun restoreNotetypeToStock(kind: StockNotetype.Kind? = null) {
val nid = notetypeId { ntid = tempModel.modelId }
undoableOp { restoreNotetypeToStock(nid, kind) }
onModelSaved()
showThemedToast(
requireContext(),
TR.cardTemplatesRestoredToDefault(),
shortLength = false,
)
}

/**
* Handles the part of the menu set by [setupCommonMenu].
* @returns whether the given item was handled
* @see [onMenuItemSelected] and [onMenuItemClick]
*/
@NeedsTest("Restore to default option")
fun handleCommonMenuItemSelected(menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.action_add -> {
Expand Down Expand Up @@ -928,6 +953,47 @@ open class CardTemplateEditor :
Timber.i("CardTemplateEditor::Card Browser Template button pressed")
openBrowserAppearance()
}
R.id.action_restore_to_default -> {
Timber.i("CardTemplateEditor:: Restore to default button pressed")

fun askUser(kind: StockNotetype.Kind? = null) {
AlertDialog.Builder(requireContext()).show {
RobozinhoD marked this conversation as resolved.
Show resolved Hide resolved
setTitle(TR.cardTemplatesRestoreToDefault())
setMessage(TR.cardTemplatesRestoreToDefaultConfirmation())
setPositiveButton(R.string.dialog_ok) { _, _ ->
launchCatchingTask {
david-allison marked this conversation as resolved.
Show resolved Hide resolved
restoreNotetypeToStock(kind)
david-allison marked this conversation as resolved.
Show resolved Hide resolved
}
}
setNegativeButton(R.string.dialog_cancel) { _, _ -> }
}
}

val originalStockKind = tempModel.notetype.optInt("originalStockKind", ORIGINAL_STOCK_KIND_UNKNOWN_VALUE)
if (originalStockKind != ORIGINAL_STOCK_KIND_UNKNOWN_VALUE) {
Timber.d("Asking to restore to original stock kind %s", originalStockKind)
askUser()
return true
}

launchCatchingTask {
Timber.d("Unknown stock kind: asking which kind to restore to")
val stockNotetypeKinds = getStockNotetypeKinds()
val stockNotetypesNames =
withCol {
stockNotetypeKinds.map { getStockNotetype(it).name }
}
AlertDialog.Builder(requireContext()).show {
setTitle(TR.cardTemplatesRestoreToDefault())
setNegativeButton(R.string.dialog_cancel) { _, _ -> }
listItems(stockNotetypesNames) { _: DialogInterface, index: Int ->
val kind = stockNotetypeKinds[index]
askUser(kind)
}
}
}
true
}
else -> {
return false
}
Expand Down
30 changes: 30 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/libanki/Notetypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,22 @@

package com.ichi2.libanki

import androidx.annotation.CheckResult
import anki.collection.OpChanges
import anki.collection.OpChangesWithId
import anki.notetypes.Notetype
import anki.notetypes.NotetypeId
import anki.notetypes.NotetypeNameId
import anki.notetypes.NotetypeNameIdUseCount
import anki.notetypes.StockNotetype
import anki.notetypes.restoreNotetypeToStockRequest
import com.google.protobuf.ByteString
import com.ichi2.anki.CrashReportService
import com.ichi2.annotations.NeedsTest
import com.ichi2.libanki.Consts.MODEL_CLOZE
import com.ichi2.libanki.Utils.checksum
import com.ichi2.libanki.backend.BackendUtils
import com.ichi2.libanki.backend.BackendUtils.fromJsonBytes
import com.ichi2.libanki.backend.BackendUtils.toJsonBytes
import com.ichi2.libanki.exception.ConfirmModSchemaException
import com.ichi2.libanki.utils.LibAnkiAlias
Expand Down Expand Up @@ -776,3 +780,29 @@ fun Collection.getNotetypeNames(): List<NotetypeNameId> = backend.getNotetypeNam
fun Collection.addNotetypeLegacy(json: ByteString): OpChangesWithId = backend.addNotetypeLegacy(json = json)

fun Collection.getStockNotetypeLegacy(kind: StockNotetype.Kind): ByteString = backend.getStockNotetypeLegacy(kind = kind)

fun Collection.getStockNotetype(kind: StockNotetype.Kind): NotetypeJson = NotetypeJson(fromJsonBytes(getStockNotetypeLegacy(kind)))

/**
* Restores a notetype to its original stock kind.
*
* @param notetypeId id of the changed notetype
* @param forceKind optional stock kind to be forced instead of the original kind.
* Older notetypes did not store their original stock kind, so we allow the UI
* to pass in an override to use when missing, or for tests.
*/
@CheckResult
fun Collection.restoreNotetypeToStock(
RobozinhoD marked this conversation as resolved.
Show resolved Hide resolved
notetypeId: NotetypeId,
forceKind: StockNotetype.Kind? = null,
): OpChanges {
val msg =
restoreNotetypeToStockRequest {
this.notetypeId = notetypeId
forceKind?.let { this.forceKind = forceKind }
}
return backend.restoreNotetypeToStock(msg)
}

@NotInLibAnki
fun getStockNotetypeKinds(): List<StockNotetype.Kind> = StockNotetype.Kind.entries.filter { it != StockNotetype.Kind.UNRECOGNIZED }
8 changes: 7 additions & 1 deletion AnkiDroid/src/main/res/menu/card_template_editor.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ankidroid="http://schemas.android.com/apk/res-auto" >
xmlns:ankidroid="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/action_confirm"
android:icon="@drawable/ic_done_white"
Expand Down Expand Up @@ -48,4 +49,9 @@
android:id="@+id/action_copy_as_markdown"
android:title="@string/copy_as_markdown"
ankidroid:showAsAction="never" />
<item
android:id="@+id/action_restore_to_default"
tools:title="Restore to default..."
ankidroid:showAsAction="never"
/>
</menu>
Loading