diff --git a/kernel/api/riff.go b/kernel/api/riff.go index dde4c45f6..0ccc67358 100644 --- a/kernel/api/riff.go +++ b/kernel/api/riff.go @@ -104,6 +104,25 @@ func reviewRiffCard(c *gin.Context) { } } +func skipReviewRiffCard(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + deckID := arg["deckID"].(string) + cardID := arg["cardID"].(string) + err := model.SkipReviewFlashcard(deckID, cardID) + if nil != err { + ret.Code = -1 + ret.Msg = err.Error() + return + } +} + func getNotebookRiffDueCards(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) diff --git a/kernel/api/router.go b/kernel/api/router.go index 8431c5a5a..b0f20efb3 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -314,6 +314,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/riff/getTreeRiffDueCards", model.CheckAuth, getTreeRiffDueCards) ginServer.Handle("POST", "/api/riff/getNotebookRiffDueCards", model.CheckAuth, getNotebookRiffDueCards) ginServer.Handle("POST", "/api/riff/reviewRiffCard", model.CheckAuth, model.CheckReadonly, reviewRiffCard) + ginServer.Handle("POST", "/api/riff/skipReviewRiffCard", model.CheckAuth, model.CheckReadonly, skipReviewRiffCard) ginServer.Handle("POST", "/api/riff/getRiffCards", model.CheckAuth, getRiffCards) ginServer.Handle("POST", "/api/riff/getTreeRiffCards", model.CheckAuth, getTreeRiffCards) ginServer.Handle("POST", "/api/riff/getNotebookRiffCards", model.CheckAuth, getNotebookRiffCards) diff --git a/kernel/model/flashcard.go b/kernel/model/flashcard.go index be50ee4f5..c040bfc42 100644 --- a/kernel/model/flashcard.go +++ b/kernel/model/flashcard.go @@ -181,8 +181,13 @@ func getCardsBlocks(cards []riff.Card, page int) (blocks []*Block, total, pageCo return } -// reviewCardCache 用于复习时缓存卡片,以便支持撤销。 -var reviewCardCache = map[string]riff.Card{} +var ( + // reviewCardCache 用于复习时缓存卡片,以便支持撤销。 + reviewCardCache = map[string]riff.Card{} + + // skipCardCache 用于复习时缓存跳过的卡片,以便支持跳过过滤。 + skipCardCache = map[string]riff.Card{} +) func ReviewFlashcard(deckID, cardID string, rating riff.Rating) (err error) { deckLock.Lock() @@ -203,6 +208,9 @@ func ReviewFlashcard(deckID, cardID string, rating riff.Rating) (err error) { // 命中缓存说明这张卡片已经复习过了,这次调用复习是撤销后再次复习 // 将缓存的卡片重新覆盖回卡包中,以恢复最开始复习前的状态 deck.SetCard(cachedCard) + + // 从跳过缓存中移除(如果上一次点的是跳过的话),如果不在跳过缓存中,说明上一次点的是复习,这里移除一下也没有副作用 + delete(skipCardCache, cardID) } else { // 首次复习该卡片,将卡片缓存以便后续支持撤销后再次复习 reviewCardCache[cardID] = card @@ -217,12 +225,32 @@ func ReviewFlashcard(deckID, cardID string, rating riff.Rating) (err error) { dueCards := getDueFlashcards(deckID) if 1 > len(dueCards) { - // 该卡包中没有待复习的卡片了,说明最后一张卡片已经复习完了,清空撤销缓存 + // 该卡包中没有待复习的卡片了,说明最后一张卡片已经复习完了,清空撤销缓存和跳过缓存 reviewCardCache = map[string]riff.Card{} + skipCardCache = map[string]riff.Card{} } return } +func SkipReviewFlashcard(deckID, cardID string) (err error) { + deckLock.Lock() + defer deckLock.Unlock() + + if syncingStorages { + err = errors.New(Conf.Language(81)) + return + } + + deck := Decks[deckID] + card := deck.GetCard(cardID) + if nil == card { + return + } + + skipCardCache[cardID] = card + return +} + type Flashcard struct { DeckID string `json:"deckID"` CardID string `json:"cardID"` @@ -286,7 +314,7 @@ func GetNotebookDueFlashcards(boxID string) (ret []*Flashcard, err error) { return } - cards := deck.Dues() + cards := getDeckDueCards(deck) now := time.Now() for _, card := range cards { blockID := card.BlockID() @@ -317,7 +345,7 @@ func GetTreeDueFlashcards(rootID string) (ret []*Flashcard, err error) { } treeBlockIDs := getTreeSubTreeChildBlocks(rootID) - cards := deck.Dues() + cards := getDeckDueCards(deck) now := time.Now() for _, card := range cards { blockID := card.BlockID() @@ -396,7 +424,7 @@ func getDueFlashcards(deckID string) (ret []*Flashcard) { return } - cards := deck.Dues() + cards := getDeckDueCards(deck) now := time.Now() for _, card := range cards { blockID := card.BlockID() @@ -416,7 +444,7 @@ func getDueFlashcards(deckID string) (ret []*Flashcard) { func getAllDueFlashcards() (ret []*Flashcard) { now := time.Now() for _, deck := range Decks { - cards := deck.Dues() + cards := getDeckDueCards(deck) for _, card := range cards { blockID := card.BlockID() if nil == treenode.GetBlockTree(blockID) { @@ -867,3 +895,17 @@ func getDeckIDs() (deckIDs []string) { } return } + +func getDeckDueCards(deck *riff.Deck) (ret []riff.Card) { + ret = []riff.Card{} + dues := deck.Dues() + + for _, c := range dues { + if nil != skipCardCache[c.ID()] { + continue + } + + ret = append(ret, c) + } + return +}