mirror of
https://github.com/ankidroid/Anki-Android.git
synced 2024-09-20 20:03:05 +02:00
Don't store collection reference in DeckTreeNode
Pass it in to processChildren() instead, which is cleaner, and will work better with the move to a backend method. Speed up deck list by rendering it with the backend This delegates to the backend to render the deck tree, instead of calculating it in Java. On @Arthur-Milchior's large collection with the daily limits turned up, the speed difference in an x86_64 sim is dramatic: 2.4s with the old Java code, and 70ms with the new Rust code. - Make deckDueList() private; switch callers to use deckDueTree() The backend only provides a deckDueTree(), and switching the calls to deckDueList() now will make migration easier in the future. Squashed from #11599
This commit is contained in:
parent
41db4eaef1
commit
5f4c8c6be2
@ -37,6 +37,7 @@ import com.ichi2.libanki.backend.exception.DeckRenameException
|
|||||||
import com.ichi2.libanki.exception.EmptyMediaException
|
import com.ichi2.libanki.exception.EmptyMediaException
|
||||||
import com.ichi2.libanki.sched.AbstractSched
|
import com.ichi2.libanki.sched.AbstractSched
|
||||||
import com.ichi2.libanki.sched.DeckDueTreeNode
|
import com.ichi2.libanki.sched.DeckDueTreeNode
|
||||||
|
import com.ichi2.libanki.sched.TreeNode
|
||||||
import com.ichi2.libanki.utils.TimeManager
|
import com.ichi2.libanki.utils.TimeManager
|
||||||
import com.ichi2.utils.FileUtil.internalizeUri
|
import com.ichi2.utils.FileUtil.internalizeUri
|
||||||
import com.ichi2.utils.JSONArray
|
import com.ichi2.utils.JSONArray
|
||||||
@ -375,28 +376,44 @@ class CardContentProvider : ContentProvider() {
|
|||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
DECKS -> {
|
DECKS -> {
|
||||||
val allDecks = col.sched.deckDueList()
|
|
||||||
val columns = projection ?: FlashCardsContract.Deck.DEFAULT_PROJECTION
|
val columns = projection ?: FlashCardsContract.Deck.DEFAULT_PROJECTION
|
||||||
val rv = MatrixCursor(columns, allDecks.size)
|
val allDecks = col.sched.deckDueTree()
|
||||||
for (deck: DeckDueTreeNode? in allDecks) {
|
val rv = MatrixCursor(columns, 1)
|
||||||
val id = deck!!.did
|
fun forEach(nodeList: List<TreeNode<DeckDueTreeNode>>, fn: (DeckDueTreeNode) -> Unit) {
|
||||||
val name = deck.fullDeckName
|
for (node in nodeList) {
|
||||||
addDeckToCursor(id, name, getDeckCountsFromDueTreeNode(deck), rv, col, columns)
|
fn(node.value)
|
||||||
|
forEach(node.children, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forEach(allDecks) {
|
||||||
|
addDeckToCursor(
|
||||||
|
it.did,
|
||||||
|
it.fullDeckName,
|
||||||
|
getDeckCountsFromDueTreeNode(it),
|
||||||
|
rv,
|
||||||
|
col,
|
||||||
|
columns
|
||||||
|
)
|
||||||
}
|
}
|
||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
DECKS_ID -> {
|
DECKS_ID -> {
|
||||||
|
|
||||||
/* Direct access deck */
|
/* Direct access deck */
|
||||||
val columns = projection ?: FlashCardsContract.Deck.DEFAULT_PROJECTION
|
val columns = projection ?: FlashCardsContract.Deck.DEFAULT_PROJECTION
|
||||||
val rv = MatrixCursor(columns, 1)
|
val rv = MatrixCursor(columns, 1)
|
||||||
val allDecks = col.sched.deckDueList()
|
val allDecks = col.sched.deckDueTree()
|
||||||
val deckId = uri.pathSegments[1].toLong()
|
val desiredDeckId = uri.pathSegments[1].toLong()
|
||||||
for (deck: DeckDueTreeNode? in allDecks) {
|
fun find(nodeList: List<TreeNode<DeckDueTreeNode>>, id: Long): DeckDueTreeNode? {
|
||||||
if (deck!!.did == deckId) {
|
for (node in nodeList) {
|
||||||
addDeckToCursor(deckId, deck.fullDeckName, getDeckCountsFromDueTreeNode(deck), rv, col, columns)
|
if (node.value.did == id) {
|
||||||
return rv
|
return node.value
|
||||||
|
}
|
||||||
|
return find(node.children, id)
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
find(allDecks, desiredDeckId)?.let {
|
||||||
|
addDeckToCursor(it.did, it.fullDeckName, getDeckCountsFromDueTreeNode(it), rv, col, columns)
|
||||||
}
|
}
|
||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
@ -413,10 +430,9 @@ class CardContentProvider : ContentProvider() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDeckCountsFromDueTreeNode(deck: DeckDueTreeNode?): JSONArray {
|
private fun getDeckCountsFromDueTreeNode(deck: DeckDueTreeNode): JSONArray {
|
||||||
@KotlinCleanup("use a scope function")
|
|
||||||
val deckCounts = JSONArray()
|
val deckCounts = JSONArray()
|
||||||
deckCounts.put(deck!!.lrnCount)
|
deckCounts.put(deck.lrnCount)
|
||||||
deckCounts.put(deck.revCount)
|
deckCounts.put(deck.revCount)
|
||||||
deckCounts.put(deck.newCount)
|
deckCounts.put(deck.newCount)
|
||||||
return deckCounts
|
return deckCounts
|
||||||
|
@ -32,7 +32,6 @@ import java.util.*
|
|||||||
* [processChildren] should be called if the children of this node are modified.
|
* [processChildren] should be called if the children of this node are modified.
|
||||||
*/
|
*/
|
||||||
abstract class AbstractDeckTreeNode(
|
abstract class AbstractDeckTreeNode(
|
||||||
val col: Collection,
|
|
||||||
/**
|
/**
|
||||||
* @return The full deck name, e.g. "A::B::C"
|
* @return The full deck name, e.g. "A::B::C"
|
||||||
*/
|
*/
|
||||||
@ -68,7 +67,7 @@ abstract class AbstractDeckTreeNode(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun processChildren(children: List<AbstractDeckTreeNode>, addRev: Boolean)
|
abstract fun processChildren(col: Collection, children: List<AbstractDeckTreeNode>, addRev: Boolean)
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val buf = StringBuffer()
|
val buf = StringBuffer()
|
||||||
|
@ -175,26 +175,23 @@ abstract class AbstractSched(val col: Collection) {
|
|||||||
*/
|
*/
|
||||||
abstract fun extendLimits(newc: Int, rev: Int)
|
abstract fun extendLimits(newc: Int, rev: Int)
|
||||||
|
|
||||||
/**
|
|
||||||
* @return [deckname, did, rev, lrn, new]
|
|
||||||
*/
|
|
||||||
abstract fun deckDueList(): List<DeckDueTreeNode>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param cancelListener A task that is potentially cancelled
|
* @param cancelListener A task that is potentially cancelled
|
||||||
* @return the due tree. null if task is cancelled
|
* @return the due tree. null only if task is cancelled
|
||||||
*/
|
*/
|
||||||
abstract fun deckDueTree(cancelListener: CancelListener?): List<TreeNode<DeckDueTreeNode>>?
|
abstract fun deckDueTree(cancelListener: CancelListener?): List<TreeNode<DeckDueTreeNode>>?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the due tree. null if task is cancelled.
|
* @return the due tree. Never null.
|
||||||
*/
|
*/
|
||||||
abstract fun deckDueTree(): List<TreeNode<DeckDueTreeNode>>
|
fun deckDueTree(): List<TreeNode<DeckDueTreeNode>> {
|
||||||
|
return deckDueTree(null)!!
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The tree of decks, without numbers
|
* @return The tree of decks, without numbers
|
||||||
*/
|
*/
|
||||||
abstract fun quickDeckDueTree(): List<TreeNode<DeckTreeNode>>
|
abstract fun<T : AbstractDeckTreeNode> quickDeckDueTree(): List<TreeNode<T>>
|
||||||
|
|
||||||
/** New count for a single deck.
|
/** New count for a single deck.
|
||||||
* @param did The deck to consider (descendants and ancestors are ignored)
|
* @param did The deck to consider (descendants and ancestors are ignored)
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/***************************************************************************************
|
||||||
|
* Copyright (c) 2012 Ankitects Pty Ltd <http://apps.ankiweb.net> *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under *
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software *
|
||||||
|
* Foundation; either version 3 of the License, or (at your option) any later *
|
||||||
|
* version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
|
||||||
|
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License along with *
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
package com.ichi2.libanki.sched
|
||||||
|
|
||||||
|
import anki.decks.DeckTreeNode
|
||||||
|
import com.ichi2.libanki.CollectionV16
|
||||||
|
import com.ichi2.libanki.utils.TimeManager
|
||||||
|
|
||||||
|
// The desktop code stores these routines in sched/base.py, and all schedulers inherit them.
|
||||||
|
// The presence of AbstractSched is going to complicate the introduction of the v3 scheduler,
|
||||||
|
// so for now these are stored in a separate file.
|
||||||
|
|
||||||
|
fun CollectionV16.deckTree(includeCounts: Boolean): DeckTreeNode {
|
||||||
|
return backend.deckTree(if (includeCounts) TimeManager.time.intTime() else 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutate the backend reply into a format expected by legacy code. This is less efficient,
|
||||||
|
* and AnkiDroid may wish to use .deckTree() in the future instead.
|
||||||
|
*/
|
||||||
|
fun CollectionV16.deckTreeLegacy(includeCounts: Boolean): List<TreeNode<DeckDueTreeNode>> {
|
||||||
|
fun toLegacyNode(node: anki.decks.DeckTreeNode, parentName: String): TreeNode<DeckDueTreeNode> {
|
||||||
|
val thisName = if (parentName.isEmpty()) {
|
||||||
|
node.name
|
||||||
|
} else {
|
||||||
|
"$parentName::${node.name}"
|
||||||
|
}
|
||||||
|
val treeNode = TreeNode(
|
||||||
|
DeckDueTreeNode(
|
||||||
|
thisName,
|
||||||
|
node.deckId,
|
||||||
|
node.reviewCount,
|
||||||
|
node.learnCount,
|
||||||
|
node.newCount,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
treeNode.children.addAll(node.childrenList.asSequence().map { toLegacyNode(it, thisName) })
|
||||||
|
return treeNode
|
||||||
|
}
|
||||||
|
return toLegacyNode(deckTree(includeCounts), "").children
|
||||||
|
}
|
@ -18,6 +18,7 @@ package com.ichi2.libanki.sched
|
|||||||
import com.ichi2.libanki.Collection
|
import com.ichi2.libanki.Collection
|
||||||
import com.ichi2.libanki.Decks
|
import com.ichi2.libanki.Decks
|
||||||
import com.ichi2.utils.KotlinCleanup
|
import com.ichi2.utils.KotlinCleanup
|
||||||
|
import net.ankiweb.rsdroid.RustCleanup
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@ -34,7 +35,8 @@ import kotlin.math.min
|
|||||||
*/
|
*/
|
||||||
@KotlinCleanup("maybe possible to remove gettres for revCount/lrnCount")
|
@KotlinCleanup("maybe possible to remove gettres for revCount/lrnCount")
|
||||||
@KotlinCleanup("rename name -> fullDeckName")
|
@KotlinCleanup("rename name -> fullDeckName")
|
||||||
class DeckDueTreeNode(col: Collection, name: String, did: Long, override var revCount: Int, override var lrnCount: Int, override var newCount: Int) : AbstractDeckTreeNode(col, name, did) {
|
@RustCleanup("after migration, consider dropping this and using backend tree structure directly")
|
||||||
|
class DeckDueTreeNode(name: String, did: Long, override var revCount: Int, override var lrnCount: Int, override var newCount: Int) : AbstractDeckTreeNode(name, did) {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return String.format(
|
return String.format(
|
||||||
Locale.US, "%s, %d, %d, %d, %d",
|
Locale.US, "%s, %d, %d, %d, %d",
|
||||||
@ -50,7 +52,7 @@ class DeckDueTreeNode(col: Collection, name: String, did: Long, override var rev
|
|||||||
newCount = max(0, min(newCount, limit))
|
newCount = max(0, min(newCount, limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processChildren(children: List<AbstractDeckTreeNode>, addRev: Boolean) {
|
override fun processChildren(col: Collection, children: List<AbstractDeckTreeNode>, addRev: Boolean) {
|
||||||
// tally up children counts
|
// tally up children counts
|
||||||
for (ch in children) {
|
for (ch in children) {
|
||||||
lrnCount += ch.lrnCount
|
lrnCount += ch.lrnCount
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
package com.ichi2.libanki.sched
|
package com.ichi2.libanki.sched
|
||||||
|
|
||||||
import com.ichi2.libanki.Collection
|
import com.ichi2.libanki.Collection
|
||||||
import com.ichi2.utils.KotlinCleanup
|
import net.ankiweb.rsdroid.RustCleanup
|
||||||
|
|
||||||
@KotlinCleanup("confusing nullability for col, verify real nullability after code related to scheduling is fully migrated to kotlin")
|
@RustCleanup("processChildren() can be removed after migrating to backend implementation")
|
||||||
class DeckTreeNode(col: Collection, name: String, did: Long) : AbstractDeckTreeNode(col, name, did) {
|
class DeckTreeNode(name: String, did: Long) : AbstractDeckTreeNode(name, did) {
|
||||||
override fun processChildren(children: List<AbstractDeckTreeNode>, addRev: Boolean) {
|
override fun processChildren(col: Collection, children: List<AbstractDeckTreeNode>, addRev: Boolean) {
|
||||||
// intentionally blank
|
// intentionally blank
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ public class Sched extends SchedV2 {
|
|||||||
* Returns [deckname, did, rev, lrn, new]
|
* Returns [deckname, did, rev, lrn, new]
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public @Nullable List<DeckDueTreeNode> deckDueList(@Nullable CancelListener cancelListener) {
|
protected @Nullable List<DeckDueTreeNode> deckDueList(@Nullable CancelListener cancelListener) {
|
||||||
_checkDay();
|
_checkDay();
|
||||||
getCol().getDecks().checkIntegrity();
|
getCol().getDecks().checkIntegrity();
|
||||||
List<Deck> allDecksSorted = getCol().getDecks().allSorted();
|
List<Deck> allDecksSorted = getCol().getDecks().allSorted();
|
||||||
@ -242,7 +242,7 @@ public class Sched extends SchedV2 {
|
|||||||
// reviews
|
// reviews
|
||||||
int rev = _revForDeck(deck.getLong("id"), rlim);
|
int rev = _revForDeck(deck.getLong("id"), rlim);
|
||||||
// save to list
|
// save to list
|
||||||
deckNodes.add(new DeckDueTreeNode(getCol(), deck.getString("name"), deck.getLong("id"), rev, lrn, _new));
|
deckNodes.add(new DeckDueTreeNode(deck.getString("name"), deck.getLong("id"), rev, lrn, _new));
|
||||||
// add deck as a parent
|
// add deck as a parent
|
||||||
lims.put(Decks.normalizeName(deck.getString("name")), new Integer[]{nlim, rlim});
|
lims.put(Decks.normalizeName(deck.getString("name")), new Integer[]{nlim, rlim});
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import android.text.TextUtils;
|
|||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.ichi2.anki.AnkiDroidApp;
|
||||||
import com.ichi2.anki.R;
|
import com.ichi2.anki.R;
|
||||||
import com.ichi2.async.CancelListener;
|
import com.ichi2.async.CancelListener;
|
||||||
import com.ichi2.async.CollectionTask;
|
import com.ichi2.async.CollectionTask;
|
||||||
@ -57,6 +58,7 @@ import com.ichi2.utils.JSONException;
|
|||||||
import com.ichi2.utils.JSONObject;
|
import com.ichi2.utils.JSONObject;
|
||||||
import com.ichi2.utils.SyncStatus;
|
import com.ichi2.utils.SyncStatus;
|
||||||
|
|
||||||
|
import net.ankiweb.rsdroid.BackendFactory;
|
||||||
import net.ankiweb.rsdroid.RustCleanup;
|
import net.ankiweb.rsdroid.RustCleanup;
|
||||||
import net.ankiweb.rsdroid.RustV1Cleanup;
|
import net.ankiweb.rsdroid.RustV1Cleanup;
|
||||||
|
|
||||||
@ -523,14 +525,14 @@ public class SchedV2 extends AbstractSched {
|
|||||||
*
|
*
|
||||||
* Return nulls when deck task is cancelled.
|
* Return nulls when deck task is cancelled.
|
||||||
*/
|
*/
|
||||||
public @NonNull List<DeckDueTreeNode> deckDueList() {
|
private @NonNull List<DeckDueTreeNode> deckDueList() {
|
||||||
return deckDueList(null);
|
return deckDueList(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overridden
|
// Overridden
|
||||||
/**
|
/**
|
||||||
* Return sorted list of all decks.*/
|
* Return sorted list of all decks.*/
|
||||||
public @Nullable List<DeckDueTreeNode> deckDueList(@Nullable CancelListener collectionTask) {
|
protected @Nullable List<DeckDueTreeNode> deckDueList(@Nullable CancelListener collectionTask) {
|
||||||
_checkDay();
|
_checkDay();
|
||||||
getCol().getDecks().checkIntegrity();
|
getCol().getDecks().checkIntegrity();
|
||||||
List<Deck> allDecksSorted = getCol().getDecks().allSorted();
|
List<Deck> allDecksSorted = getCol().getDecks().allSorted();
|
||||||
@ -561,7 +563,7 @@ public class SchedV2 extends AbstractSched {
|
|||||||
int rlim = _deckRevLimitSingle(deck, plim, false);
|
int rlim = _deckRevLimitSingle(deck, plim, false);
|
||||||
int rev = _revForDeck(deck.getLong("id"), rlim, childMap);
|
int rev = _revForDeck(deck.getLong("id"), rlim, childMap);
|
||||||
// save to list
|
// save to list
|
||||||
deckNodes.add(new DeckDueTreeNode(getCol(), deck.getString("name"), deck.getLong("id"), rev, lrn, _new));
|
deckNodes.add(new DeckDueTreeNode(deck.getString("name"), deck.getLong("id"), rev, lrn, _new));
|
||||||
// add deck as a parent
|
// add deck as a parent
|
||||||
lims.put(Decks.normalizeName(deck.getString("name")), new Integer[]{nlim, rlim});
|
lims.put(Decks.normalizeName(deck.getString("name")), new Integer[]{nlim, rlim});
|
||||||
}
|
}
|
||||||
@ -574,13 +576,15 @@ public class SchedV2 extends AbstractSched {
|
|||||||
requires multiple database access by deck. Ignoring this number
|
requires multiple database access by deck. Ignoring this number
|
||||||
lead to the creation of a tree more quickly.*/
|
lead to the creation of a tree more quickly.*/
|
||||||
@Override
|
@Override
|
||||||
public @NonNull List<TreeNode<DeckTreeNode>> quickDeckDueTree() {
|
public @NonNull
|
||||||
// Similar to deckDueTree, ignoring the numbers
|
List<? extends TreeNode<? extends AbstractDeckTreeNode>> quickDeckDueTree() {
|
||||||
|
if (!BackendFactory.getDefaultLegacySchema()) {
|
||||||
|
return BackendSchedKt.deckTreeLegacy(getCol().getNewBackend(), false);
|
||||||
|
}
|
||||||
// Similar to deckDueList
|
// Similar to deckDueList
|
||||||
ArrayList<DeckTreeNode> allDecksSorted = new ArrayList<>();
|
ArrayList<DeckTreeNode> allDecksSorted = new ArrayList<>();
|
||||||
for (JSONObject deck : getCol().getDecks().allSorted()) {
|
for (JSONObject deck : getCol().getDecks().allSorted()) {
|
||||||
DeckTreeNode g = new DeckTreeNode(getCol(), deck.getString("name"), deck.getLong("id"));
|
DeckTreeNode g = new DeckTreeNode(deck.getString("name"), deck.getLong("id"));
|
||||||
allDecksSorted.add(g);
|
allDecksSorted.add(g);
|
||||||
}
|
}
|
||||||
// End of the similar part.
|
// End of the similar part.
|
||||||
@ -588,18 +592,19 @@ public class SchedV2 extends AbstractSched {
|
|||||||
return _groupChildren(allDecksSorted, false);
|
return _groupChildren(allDecksSorted, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public @NonNull List<TreeNode<DeckDueTreeNode>> deckDueTree() {
|
|
||||||
return deckDueTree(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@RustCleanup("enable for v2 once backend is updated to 2.1.41+")
|
||||||
|
@RustCleanup("once both v1 and v2 are using backend, cancelListener can be removed")
|
||||||
public List<TreeNode<DeckDueTreeNode>> deckDueTree(@Nullable CancelListener cancelListener) {
|
public List<TreeNode<DeckDueTreeNode>> deckDueTree(@Nullable CancelListener cancelListener) {
|
||||||
List<DeckDueTreeNode> allDecksSorted = deckDueList(cancelListener);
|
if (!BackendFactory.getDefaultLegacySchema()) {
|
||||||
if (allDecksSorted == null) {
|
return BackendSchedKt.deckTreeLegacy(getCol().getNewBackend(), true);
|
||||||
return null;
|
} else {
|
||||||
|
List<DeckDueTreeNode> allDecksSorted = deckDueList(cancelListener);
|
||||||
|
if (allDecksSorted == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return _groupChildren(allDecksSorted, true);
|
||||||
}
|
}
|
||||||
return _groupChildren(allDecksSorted, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -666,7 +671,7 @@ public class SchedV2 extends AbstractSched {
|
|||||||
TreeNode<T> toAdd = new TreeNode<>(child);
|
TreeNode<T> toAdd = new TreeNode<>(child);
|
||||||
toAdd.getChildren().addAll(childrenNode);
|
toAdd.getChildren().addAll(childrenNode);
|
||||||
List<T> childValues = childrenNode.stream().map(TreeNode::getValue).collect(Collectors.toList());
|
List<T> childValues = childrenNode.stream().map(TreeNode::getValue).collect(Collectors.toList());
|
||||||
child.processChildren(childValues, "std".equals(getName()));
|
child.processChildren(getCol(), childValues, "std".equals(getName()));
|
||||||
|
|
||||||
sortedChildren.add(toAdd);
|
sortedChildren.add(toAdd);
|
||||||
}
|
}
|
||||||
|
@ -449,7 +449,7 @@ public class Syncer {
|
|||||||
mCol.getModels().save();
|
mCol.getModels().save();
|
||||||
}
|
}
|
||||||
// check for missing parent decks
|
// check for missing parent decks
|
||||||
mCol.getSched().deckDueList();
|
mCol.getSched().quickDeckDueTree();
|
||||||
// return summary of deck
|
// return summary of deck
|
||||||
JSONArray check = new JSONArray();
|
JSONArray check = new JSONArray();
|
||||||
JSONArray counts = new JSONArray();
|
JSONArray counts = new JSONArray();
|
||||||
|
@ -204,7 +204,7 @@ public class AbstractSchedTest extends RobolectricTest {
|
|||||||
addDeckWithExactName(child);
|
addDeckWithExactName(child);
|
||||||
|
|
||||||
getCol().getDecks().checkIntegrity();
|
getCol().getDecks().checkIntegrity();
|
||||||
assertDoesNotThrow(() -> getCol().getSched().deckDueList());
|
assertDoesNotThrow(() -> getCol().getSched().deckDueTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,16 +112,16 @@ public class SchedV2Test extends RobolectricTest {
|
|||||||
// These matched the previous Java data
|
// These matched the previous Java data
|
||||||
// These may want to be changed back
|
// These may want to be changed back
|
||||||
List<TreeNode<DeckDueTreeNode>> expected = new ArrayList<>();
|
List<TreeNode<DeckDueTreeNode>> expected = new ArrayList<>();
|
||||||
DeckDueTreeNode caz = new DeckDueTreeNode(col, "cmxieunwoogyxsctnjmv::abcdefgh::ZYXW", 1596783600480L, 0, 0, 0);
|
DeckDueTreeNode caz = new DeckDueTreeNode("cmxieunwoogyxsctnjmv::abcdefgh::ZYXW", 1596783600480L, 0, 0, 0);
|
||||||
DeckDueTreeNode ca = new DeckDueTreeNode(col, "cmxieunwoogyxsctnjmv::abcdefgh", 1596783600460L, 0, 0, 0);
|
DeckDueTreeNode ca = new DeckDueTreeNode("cmxieunwoogyxsctnjmv::abcdefgh", 1596783600460L, 0, 0, 0);
|
||||||
DeckDueTreeNode ci = new DeckDueTreeNode(col, "cmxieunwoogyxsctnjmv::INSBGDS", 1596783600500L, 0, 0, 0);
|
DeckDueTreeNode ci = new DeckDueTreeNode("cmxieunwoogyxsctnjmv::INSBGDS", 1596783600500L, 0, 0, 0);
|
||||||
DeckDueTreeNode c = new DeckDueTreeNode(col, "cmxieunwoogyxsctnjmv", 1596783600440L, 0, 0, 0);
|
DeckDueTreeNode c = new DeckDueTreeNode("cmxieunwoogyxsctnjmv", 1596783600440L, 0, 0, 0);
|
||||||
DeckDueTreeNode defaul = new DeckDueTreeNode(col, "Default", 1, 0, 0, 0);
|
DeckDueTreeNode defaul = new DeckDueTreeNode("Default", 1, 0, 0, 0);
|
||||||
DeckDueTreeNode s = new DeckDueTreeNode(col, "scxipjiyozczaaczoawo", 1596783600420L, 0, 0, 0);
|
DeckDueTreeNode s = new DeckDueTreeNode("scxipjiyozczaaczoawo", 1596783600420L, 0, 0, 0);
|
||||||
DeckDueTreeNode f = new DeckDueTreeNode(col, "blank::foobar", 1596783600540L, 0, 0, 0);
|
DeckDueTreeNode f = new DeckDueTreeNode("blank::foobar", 1596783600540L, 0, 0, 0);
|
||||||
DeckDueTreeNode b = new DeckDueTreeNode(col, "blank", 1596783600520L, 0, 0, 0);
|
DeckDueTreeNode b = new DeckDueTreeNode("blank", 1596783600520L, 0, 0, 0);
|
||||||
DeckDueTreeNode aBlank = new DeckDueTreeNode(col, "A::blank", 1596783600580L, 0, 0, 0);
|
DeckDueTreeNode aBlank = new DeckDueTreeNode("A::blank", 1596783600580L, 0, 0, 0);
|
||||||
DeckDueTreeNode a = new DeckDueTreeNode(col, "A", 1596783600560L, 0, 0, 0);
|
DeckDueTreeNode a = new DeckDueTreeNode("A", 1596783600560L, 0, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
TreeNode<DeckDueTreeNode> cazNode = new TreeNode<>(caz);
|
TreeNode<DeckDueTreeNode> cazNode = new TreeNode<>(caz);
|
||||||
@ -135,7 +135,7 @@ public class SchedV2Test extends RobolectricTest {
|
|||||||
|
|
||||||
// add "caz" to "ca"
|
// add "caz" to "ca"
|
||||||
caNode.getChildren().add(cazNode);
|
caNode.getChildren().add(cazNode);
|
||||||
caNode.getValue().processChildren(Collections.singletonList(cazNode.getValue()), addRev);
|
caNode.getValue().processChildren(col, Collections.singletonList(cazNode.getValue()), addRev);
|
||||||
|
|
||||||
// add "ca" and "ci" to "c"
|
// add "ca" and "ci" to "c"
|
||||||
cNode.getChildren().add(caNode);
|
cNode.getChildren().add(caNode);
|
||||||
@ -143,15 +143,15 @@ public class SchedV2Test extends RobolectricTest {
|
|||||||
ArrayList<DeckDueTreeNode> cChildren = new ArrayList<>();
|
ArrayList<DeckDueTreeNode> cChildren = new ArrayList<>();
|
||||||
cChildren.add(caNode.getValue());
|
cChildren.add(caNode.getValue());
|
||||||
cChildren.add(ciNode.getValue());
|
cChildren.add(ciNode.getValue());
|
||||||
cNode.getValue().processChildren(cChildren, addRev);
|
cNode.getValue().processChildren(col, cChildren, addRev);
|
||||||
|
|
||||||
// add "f" to "b"
|
// add "f" to "b"
|
||||||
bNode.getChildren().add(fNode);
|
bNode.getChildren().add(fNode);
|
||||||
bNode.getValue().processChildren(Collections.singletonList(fNode.getValue()), addRev);
|
bNode.getValue().processChildren(col, Collections.singletonList(fNode.getValue()), addRev);
|
||||||
|
|
||||||
// add "A::" to "A"
|
// add "A::" to "A"
|
||||||
aNode.getChildren().add(aBlankNode);
|
aNode.getChildren().add(aBlankNode);
|
||||||
aNode.getValue().processChildren(Collections.singletonList(aBlankNode.getValue()), addRev);
|
aNode.getValue().processChildren(col, Collections.singletonList(aBlankNode.getValue()), addRev);
|
||||||
|
|
||||||
expected.add(aNode);
|
expected.add(aNode);
|
||||||
expected.add(bNode);
|
expected.add(bNode);
|
||||||
@ -822,8 +822,12 @@ public class SchedV2Test extends RobolectricTest {
|
|||||||
c.flush();
|
c.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// position 0 is default deck. Different from upstream
|
int parentIndex = 0;
|
||||||
TreeNode<DeckDueTreeNode> tree = col.getSched().deckDueTree().get(1);
|
if (BackendFactory.getDefaultLegacySchema()) {
|
||||||
|
// position 0 is default deck. Different from upstream
|
||||||
|
parentIndex = 1;
|
||||||
|
}
|
||||||
|
TreeNode<DeckDueTreeNode> tree = col.getSched().deckDueTree().get(parentIndex);
|
||||||
// (('parent', 1514457677462, 5, 0, 0, (('child', 1514457677463, 5, 0, 0, ()),)))
|
// (('parent', 1514457677462, 5, 0, 0, (('child', 1514457677463, 5, 0, 0, ()),)))
|
||||||
assertEquals("parent", tree.getValue().getFullDeckName());
|
assertEquals("parent", tree.getValue().getFullDeckName());
|
||||||
assertEquals(5, tree.getValue().getRevCount()); // paren, tree.review_count)t
|
assertEquals(5, tree.getValue().getRevCount()); // paren, tree.review_count)t
|
||||||
@ -839,7 +843,7 @@ public class SchedV2Test extends RobolectricTest {
|
|||||||
col.getSched().answerCard(c, BUTTON_THREE);
|
col.getSched().answerCard(c, BUTTON_THREE);
|
||||||
assertEquals(new Counts(0, 0, 9), col.getSched().counts());
|
assertEquals(new Counts(0, 0, 9), col.getSched().counts());
|
||||||
|
|
||||||
tree = col.getSched().deckDueTree().get(1);
|
tree = col.getSched().deckDueTree().get(parentIndex);
|
||||||
assertEquals(4, tree.getValue().getRevCount());
|
assertEquals(4, tree.getValue().getRevCount());
|
||||||
assertEquals(9, tree.getChildren().get(0).getValue().getRevCount());
|
assertEquals(9, tree.getChildren().get(0).getValue().getRevCount());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user