diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json
index 85b8622d4..f0b616f82 100644
--- a/app/appearance/langs/en_US.json
+++ b/app/appearance/langs/en_US.json
@@ -1,4 +1,9 @@
{
+ "reviewMode": "Review mode",
+ "reviewModeTip": "Select the order in which new and old cards appear during review",
+ "reviewMode0": "New and old mix",
+ "reviewMode1": "New first",
+ "reviewMode2": "Old first",
"fileAnnoRefPlaceholder": "Please enter block ID",
"addToDatabase": "Add to Database",
"clearContext": "Clear context",
diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json
index 59c25e9eb..4514ed217 100644
--- a/app/appearance/langs/es_ES.json
+++ b/app/appearance/langs/es_ES.json
@@ -1,4 +1,9 @@
{
+ "reviewMode": "Modo de revisión",
+ "reviewModeTip": "Seleccione el orden en que aparecen las tarjetas nuevas y antiguas durante la revisión",
+ "reviewMode0": "Nuevo y viejo mezclado",
+ "reviewMode1": "Nuevo primero",
+ "reviewMode2": "Viejo primero",
"fileAnnoRefPlaceholder": "Ingrese el ID del bloque",
"addToDatabase": "Agregar a la base de datos",
"clearContext": "Borrar contexto",
diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json
index b5cc7d9f1..1b2a87bcc 100644
--- a/app/appearance/langs/fr_FR.json
+++ b/app/appearance/langs/fr_FR.json
@@ -1,4 +1,9 @@
{
+ "reviewMode": "Mode de révision",
+ "reviewModeTip": "Sélectionnez l'ordre dans lequel les nouvelles et anciennes cartes apparaissent lors de la révision",
+ "reviewMode0": "Nouveau et ancien mélange",
+ "reviewMode1": "Nouveau d'abord",
+ "reviewMode2": "Ancien d'abord",
"fileAnnoRefPlaceholder": "Veuillez saisir l'ID de bloc",
"addToDatabase": "Ajouter à la base de données",
"clearContext": "Effacer le contexte",
diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json
index 46067e612..eb478b460 100644
--- a/app/appearance/langs/zh_CHT.json
+++ b/app/appearance/langs/zh_CHT.json
@@ -1,4 +1,9 @@
{
+ "reviewMode": "複習模式",
+ "reviewModeTip": "選擇複習時新卡和舊卡出現的順序",
+ "reviewMode0": "新舊混合",
+ "reviewMode1": "新卡優先",
+ "reviewMode2": "舊卡優先",
"fileAnnoRefPlaceholder": "請輸入區塊 ID",
"addToDatabase": "新增至資料庫",
"clearContext": "清空上下文",
diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json
index 7dbde13d2..42834a091 100644
--- a/app/appearance/langs/zh_CN.json
+++ b/app/appearance/langs/zh_CN.json
@@ -1,4 +1,9 @@
{
+ "reviewMode": "复习模式",
+ "reviewModeTip": "选择复习时新卡和旧卡出现的顺序",
+ "reviewMode0": "新旧混合",
+ "reviewMode1": "新卡优先",
+ "reviewMode2": "旧卡优先",
"fileAnnoRefPlaceholder": "请输入块 ID",
"addToDatabase": "添加到数据库",
"clearContext": "清空上下文",
diff --git a/app/src/config/flashcard.ts b/app/src/config/flashcard.ts
index adb80903e..5be878b04 100644
--- a/app/src/config/flashcard.ts
+++ b/app/src/config/flashcard.ts
@@ -42,7 +42,19 @@ export const flashcard = {
-`;
+
+
+
+ ${window.siyuan.languages.reviewMode}
+
${window.siyuan.languages.reviewModeTip}
+
+
+
+
`;
/// #if MOBILE
responsiveHTML = `${responsiveHTML}
${window.siyuan.languages.flashcardNewCardLimit}
@@ -119,9 +131,10 @@ export const flashcard = {
return responsiveHTML;
},
bindEvent: () => {
- flashcard.element.querySelectorAll("input").forEach((item) => {
+ flashcard.element.querySelectorAll("input, select.b3-select").forEach((item) => {
item.addEventListener("change", () => {
fetchPost("/api/setting/setFlashcard", {
+ reviewMode: parseInt((flashcard.element.querySelector("#reviewMode") as HTMLSelectElement).value),
newCardLimit: parseInt((flashcard.element.querySelector("#newCardLimit") as HTMLInputElement).value),
reviewCardLimit: parseInt((flashcard.element.querySelector("#reviewCardLimit") as HTMLInputElement).value),
mark: (flashcard.element.querySelector("#mark") as HTMLInputElement).checked,
diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts
index 0de21a661..f731dda7e 100644
--- a/app/src/types/index.d.ts
+++ b/app/src/types/index.d.ts
@@ -716,6 +716,7 @@ interface IConfig {
superBlock: boolean
heading: boolean
deck: boolean
+ reviewMode: number
requestRetention: number
maximumInterval: number
weights: string
diff --git a/kernel/conf/flashcard.go b/kernel/conf/flashcard.go
index 85e7021bd..d56bb42e2 100644
--- a/kernel/conf/flashcard.go
+++ b/kernel/conf/flashcard.go
@@ -30,6 +30,7 @@ type Flashcard struct {
SuperBlock bool `json:"superBlock"` // 是否启用超级块制卡 https://github.com/siyuan-note/siyuan/issues/7702
Heading bool `json:"heading"` // 是否启用标题块制卡 https://github.com/siyuan-note/siyuan/issues/9005
Deck bool `json:"deck"` // 是否启用卡包制卡 https://github.com/siyuan-note/siyuan/issues/7724
+ ReviewMode int `json:"reviewMode"` // 复习模式,0:新旧混合,1:新卡优先,2:旧卡优先 https://github.com/siyuan-note/siyuan/issues/10303
// Apply result optimized by FSRS optimizer https://github.com/siyuan-note/siyuan/issues/9309
RequestRetention float64 `json:"requestRetention"`
@@ -55,6 +56,7 @@ func NewFlashcard() *Flashcard {
SuperBlock: true,
Heading: true,
Deck: false,
+ ReviewMode: 0,
RequestRetention: param.RequestRetention,
MaximumInterval: int(param.MaximumInterval),
Weights: weightsBuilder.String(),
diff --git a/kernel/model/flashcard.go b/kernel/model/flashcard.go
index 711e155ae..2ff66c32f 100644
--- a/kernel/model/flashcard.go
+++ b/kernel/model/flashcard.go
@@ -490,7 +490,7 @@ func GetNotebookDueFlashcards(boxID string, reviewedCardIDs []string) (ret []*Fl
return
}
- cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, treeBlockIDs, Conf.Flashcard.NewCardLimit, Conf.Flashcard.ReviewCardLimit)
+ cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, treeBlockIDs, Conf.Flashcard.NewCardLimit, Conf.Flashcard.ReviewCardLimit, Conf.Flashcard.ReviewMode)
now := time.Now()
for _, card := range cards {
ret = append(ret, newFlashcard(card, card.BlockID(), builtinDeckID, now))
@@ -535,7 +535,7 @@ func GetTreeDueFlashcards(rootID string, reviewedCardIDs []string) (ret []*Flash
}
}
- cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, treeBlockIDs, newCardLimit, reviewCardLimit)
+ cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, treeBlockIDs, newCardLimit, reviewCardLimit, Conf.Flashcard.ReviewMode)
now := time.Now()
for _, card := range cards {
ret = append(ret, newFlashcard(card, card.BlockID(), builtinDeckID, now))
@@ -606,7 +606,7 @@ func getDueFlashcards(deckID string, reviewedCardIDs []string) (ret []*Flashcard
return
}
- cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, nil, Conf.Flashcard.NewCardLimit, Conf.Flashcard.ReviewCardLimit)
+ cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, nil, Conf.Flashcard.NewCardLimit, Conf.Flashcard.ReviewCardLimit, Conf.Flashcard.ReviewMode)
now := time.Now()
for _, card := range cards {
ret = append(ret, newFlashcard(card, card.BlockID(), deckID, now))
@@ -623,7 +623,7 @@ func getDueFlashcards(deckID string, reviewedCardIDs []string) (ret []*Flashcard
func getAllDueFlashcards(reviewedCardIDs []string) (ret []*Flashcard, unreviewedCount, unreviewedNewCardCount, unreviewedOldCardCount int) {
now := time.Now()
for _, deck := range Decks {
- cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, nil, Conf.Flashcard.NewCardLimit, Conf.Flashcard.ReviewCardLimit)
+ cards, unreviewedCnt, unreviewedNewCardCnt, unreviewedOldCardCnt := getDeckDueCards(deck, reviewedCardIDs, nil, Conf.Flashcard.NewCardLimit, Conf.Flashcard.ReviewCardLimit, Conf.Flashcard.ReviewMode)
unreviewedCount += unreviewedCnt
unreviewedNewCardCount += unreviewedNewCardCnt
unreviewedOldCardCount += unreviewedOldCardCnt
@@ -988,8 +988,10 @@ func getDeckIDs() (deckIDs []string) {
return
}
-func getDeckDueCards(deck *riff.Deck, reviewedCardIDs, blockIDs []string, newCardLimit, reviewCardLimit int) (ret []riff.Card, unreviewedCount, unreviewedNewCardCountInRound, unreviewedOldCardCountInRound int) {
+func getDeckDueCards(deck *riff.Deck, reviewedCardIDs, blockIDs []string, newCardLimit, reviewCardLimit, reviewMode int) (ret []riff.Card, unreviewedCount, unreviewedNewCardCountInRound, unreviewedOldCardCountInRound int) {
ret = []riff.Card{}
+ var retNew, retOld []riff.Card
+
dues := deck.Dues()
var tmp []riff.Card
@@ -1060,15 +1062,28 @@ func getDeckDueCards(deck *riff.Deck, reviewedCardIDs, blockIDs []string, newCar
}
newCount++
+ retNew = append(retNew, c)
} else {
if reviewCount >= reviewCardLimit {
continue
}
reviewCount++
+ retOld = append(retOld, c)
}
ret = append(ret, c)
}
+
+ switch reviewMode {
+ case 1: // 优先复习新卡
+ ret = nil
+ ret = append(ret, retNew...)
+ ret = append(ret, retOld...)
+ case 2: // 优先复习旧卡
+ ret = nil
+ ret = append(ret, retOld...)
+ ret = append(ret, retNew...)
+ }
return
}