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 }