Переглянути джерело

:art: Show count in spaced repetition tree filter floating window https://github.com/siyuan-note/siyuan/issues/8202

Liang Ding 2 роки тому
батько
коміт
c2dba92f4d
5 змінених файлів з 86 додано та 45 видалено
  1. 3 3
      kernel/go.mod
  2. 10 6
      kernel/go.sum
  3. 3 0
      kernel/model/box.go
  4. 36 29
      kernel/model/file.go
  5. 34 7
      kernel/model/flashcard.go

+ 3 - 3
kernel/go.mod

@@ -38,7 +38,7 @@ require (
 	github.com/mitchellh/go-ps v1.0.0
 	github.com/mssola/user_agent v0.6.0
 	github.com/olahol/melody v1.1.3
-	github.com/open-spaced-repetition/go-fsrs v0.1.0
+	github.com/open-spaced-repetition/go-fsrs v0.1.1
 	github.com/panjf2000/ants/v2 v2.7.3
 	github.com/patrickmn/go-cache v2.1.0+incompatible
 	github.com/radovskyb/watcher v1.0.7
@@ -50,7 +50,7 @@ require (
 	github.com/siyuan-note/filelock v0.0.0-20230501032014-b981a05568ef
 	github.com/siyuan-note/httpclient v0.0.0-20230501032226-9e9018416f53
 	github.com/siyuan-note/logging v0.0.0-20230327073243-ebe83aec1493
-	github.com/siyuan-note/riff v0.0.0-20230224144841-cfbe0748ddb7
+	github.com/siyuan-note/riff v0.0.0-20230508133423-21cd63a7ef20
 	github.com/steambap/captcha v1.4.1
 	github.com/studio-b12/gowebdav v0.0.0-20230203202212-3282f94193f2
 	github.com/vmihailenco/msgpack/v5 v5.3.5
@@ -131,7 +131,7 @@ require (
 	golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect
 	golang.org/x/net v0.9.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
-	golang.org/x/sys v0.7.0 // indirect
+	golang.org/x/sys v0.8.0 // indirect
 	golang.org/x/tools v0.8.0 // indirect
 	google.golang.org/protobuf v1.29.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect

+ 10 - 6
kernel/go.sum

@@ -226,8 +226,8 @@ github.com/olahol/melody v1.1.3/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7Cv
 github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
 github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
 github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
-github.com/open-spaced-repetition/go-fsrs v0.1.0 h1:6H1nCuxuR9p/GmKji0zET1uT5KDwOmW++k7jgr8L0Gk=
-github.com/open-spaced-repetition/go-fsrs v0.1.0/go.mod h1:H07GOB0A1OBeu3401x8qWKGaa43QjfrDoWy9nba7QCc=
+github.com/open-spaced-repetition/go-fsrs v0.1.1 h1:lsUeslUmA2omWqUzRDVLh4pijilUgD8TrylxaLDcXFs=
+github.com/open-spaced-repetition/go-fsrs v0.1.1/go.mod h1:H07GOB0A1OBeu3401x8qWKGaa43QjfrDoWy9nba7QCc=
 github.com/panjf2000/ants/v2 v2.7.3 h1:rHQ0hH0DQvuNUqqlWIMJtkMcDuL1uQAfpX2mIhQ5/s0=
 github.com/panjf2000/ants/v2 v2.7.3/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8=
 github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
@@ -289,8 +289,12 @@ github.com/siyuan-note/httpclient v0.0.0-20230501032226-9e9018416f53 h1:CXYTR4Qh
 github.com/siyuan-note/httpclient v0.0.0-20230501032226-9e9018416f53/go.mod h1:S/pXlPZYCJTOZjmdmQyVga//24x3XEM+MG8vIYO26gw=
 github.com/siyuan-note/logging v0.0.0-20230327073243-ebe83aec1493 h1:oaN5b0WDFkjdBgGxmmBnMrtZxaJ76LZLwhQSZnznJMI=
 github.com/siyuan-note/logging v0.0.0-20230327073243-ebe83aec1493/go.mod h1:6mRFtAAvYPn3cDzqvyv+t8BVPGqpONDMMb5ywOhY1D4=
-github.com/siyuan-note/riff v0.0.0-20230224144841-cfbe0748ddb7 h1:Kr8hhMhr6v+U24TMDCP5WdP4dWrXm5maar+TycTZs9I=
-github.com/siyuan-note/riff v0.0.0-20230224144841-cfbe0748ddb7/go.mod h1:XJtLlKCr8cZE+lzykM4edHHih92M9M50UNw/nDLYRN8=
+github.com/siyuan-note/riff v0.0.0-20230508130104-373b932395bc h1:wTLamZP/NgBvfyAXrePWlwt3WOUgWSBtGCQTiCqcbYQ=
+github.com/siyuan-note/riff v0.0.0-20230508130104-373b932395bc/go.mod h1:XJtLlKCr8cZE+lzykM4edHHih92M9M50UNw/nDLYRN8=
+github.com/siyuan-note/riff v0.0.0-20230508132857-8b47ce84ef09 h1:WcnK8pGTRXngW5UG2gY344mkJwmoVQYRyL44AmQopCM=
+github.com/siyuan-note/riff v0.0.0-20230508132857-8b47ce84ef09/go.mod h1:XJtLlKCr8cZE+lzykM4edHHih92M9M50UNw/nDLYRN8=
+github.com/siyuan-note/riff v0.0.0-20230508133423-21cd63a7ef20 h1:p3jeBOabPCMwbmivIC/JKbtW2iwqUJOlYKqQf5pvx8w=
+github.com/siyuan-note/riff v0.0.0-20230508133423-21cd63a7ef20/go.mod h1:XJtLlKCr8cZE+lzykM4edHHih92M9M50UNw/nDLYRN8=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v1.6.7 h1:I6tZjLXD2Q1kjvNbIzB1wvQBsXmKXiVrhpRE8ZjP5jY=
@@ -410,8 +414,8 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
-golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

+ 3 - 0
kernel/model/box.go

@@ -53,6 +53,9 @@ type Box struct {
 	SortMode int    `json:"sortMode"`
 	Closed   bool   `json:"closed"`
 
+	NewFlashcardCount int `json:"newFlashcardCount"`
+	DueFlashcardCount int `json:"dueFlashcardCount"`
+
 	historyGenerated int64 // 最近一次历史生成时间
 }
 

+ 36 - 29
kernel/model/file.go

@@ -48,23 +48,25 @@ import (
 )
 
 type File struct {
-	Path         string `json:"path"`
-	Name         string `json:"name"` // 标题,即 ial["title"]
-	Icon         string `json:"icon"`
-	Name1        string `json:"name1"` // 命名,即 ial["name"]
-	Alias        string `json:"alias"`
-	Memo         string `json:"memo"`
-	Bookmark     string `json:"bookmark"`
-	ID           string `json:"id"`
-	Count        int    `json:"count"`
-	Size         uint64 `json:"size"`
-	HSize        string `json:"hSize"`
-	Mtime        int64  `json:"mtime"`
-	CTime        int64  `json:"ctime"`
-	HMtime       string `json:"hMtime"`
-	HCtime       string `json:"hCtime"`
-	Sort         int    `json:"sort"`
-	SubFileCount int    `json:"subFileCount"`
+	Path              string `json:"path"`
+	Name              string `json:"name"` // 标题,即 ial["title"]
+	Icon              string `json:"icon"`
+	Name1             string `json:"name1"` // 命名,即 ial["name"]
+	Alias             string `json:"alias"`
+	Memo              string `json:"memo"`
+	Bookmark          string `json:"bookmark"`
+	ID                string `json:"id"`
+	Count             int    `json:"count"`
+	Size              uint64 `json:"size"`
+	HSize             string `json:"hSize"`
+	Mtime             int64  `json:"mtime"`
+	CTime             int64  `json:"ctime"`
+	HMtime            string `json:"hMtime"`
+	HCtime            string `json:"hCtime"`
+	Sort              int    `json:"sort"`
+	SubFileCount      int    `json:"subFileCount"`
+	NewFlashcardCount int    `json:"newFlashcardCount"`
+	DueFlashcardCount int    `json:"dueFlashcardCount"`
 }
 
 func (box *Box) docFromFileInfo(fileInfo *FileInfo, ial map[string]string) (ret *File) {
@@ -144,13 +146,11 @@ func (box *Box) moveCorruptedData(filePath string) {
 func SearchDocsByKeyword(keyword string, flashcard bool) (ret []map[string]string) {
 	ret = []map[string]string{}
 
-	var deckBlockIDs []string
 	if flashcard {
 		deck := Decks[builtinDeckID]
 		if nil == deck {
 			return
 		}
-		deckBlockIDs = deck.GetBlockIDs()
 	}
 
 	openedBoxes := Conf.GetOpenedBoxes()
@@ -164,8 +164,9 @@ func SearchDocsByKeyword(keyword string, flashcard bool) (ret []map[string]strin
 		for _, box := range boxes {
 			if strings.Contains(box.Name, keyword) {
 				if flashcard {
-					if isBoxContainFlashcard(box.ID, deckBlockIDs) {
-						ret = append(ret, map[string]string{"path": "/", "hPath": box.Name + "/", "box": box.ID, "boxIcon": box.Icon})
+					newFlashcardCount, dueFlashcardCount, containFlashcard := countBoxFlashcard(box.ID)
+					if containFlashcard {
+						ret = append(ret, map[string]string{"path": "/", "hPath": box.Name + "/", "box": box.ID, "boxIcon": box.Icon, "newFlashcardCount": strconv.Itoa(newFlashcardCount), "dueFlashcardCount": strconv.Itoa(dueFlashcardCount)})
 					}
 				} else {
 					ret = append(ret, map[string]string{"path": "/", "hPath": box.Name + "/", "box": box.ID, "boxIcon": box.Icon})
@@ -184,8 +185,9 @@ func SearchDocsByKeyword(keyword string, flashcard bool) (ret []map[string]strin
 	} else {
 		for _, box := range boxes {
 			if flashcard {
-				if isBoxContainFlashcard(box.ID, deckBlockIDs) {
-					ret = append(ret, map[string]string{"path": "/", "hPath": box.Name + "/", "box": box.ID, "boxIcon": box.Icon})
+				newFlashcardCount, dueFlashcardCount, containFlashcard := countBoxFlashcard(box.ID)
+				if containFlashcard {
+					ret = append(ret, map[string]string{"path": "/", "hPath": box.Name + "/", "box": box.ID, "boxIcon": box.Icon, "newFlashcardCount": strconv.Itoa(newFlashcardCount), "dueFlashcardCount": strconv.Itoa(dueFlashcardCount)})
 				}
 			} else {
 				ret = append(ret, map[string]string{"path": "/", "hPath": box.Name + "/", "box": box.ID, "boxIcon": box.Icon})
@@ -200,8 +202,9 @@ func SearchDocsByKeyword(keyword string, flashcard bool) (ret []map[string]strin
 		}
 		hPath := b.Name + rootBlock.HPath
 		if flashcard {
-			if isTreeContainFlashcard(rootBlock.ID, deckBlockIDs) {
-				ret = append(ret, map[string]string{"path": rootBlock.Path, "hPath": hPath, "box": rootBlock.Box, "boxIcon": b.Icon})
+			newFlashcardCount, dueFlashcardCount, containFlashcard := countTreeFlashcard(rootBlock.ID)
+			if containFlashcard {
+				ret = append(ret, map[string]string{"path": rootBlock.Path, "hPath": hPath, "box": rootBlock.Box, "boxIcon": b.Icon, "newFlashcardCount": strconv.Itoa(newFlashcardCount), "dueFlashcardCount": strconv.Itoa(dueFlashcardCount)})
 			}
 		} else {
 			ret = append(ret, map[string]string{"path": rootBlock.Path, "hPath": hPath, "box": rootBlock.Box, "boxIcon": b.Icon})
@@ -229,13 +232,11 @@ func ListDocTree(boxID, path string, sortMode int, flashcard bool, maxListCount
 
 	ret = []*File{}
 
-	var deckBlockIDs []string
 	if flashcard {
 		deck := Decks[builtinDeckID]
 		if nil == deck {
 			return
 		}
-		deckBlockIDs = deck.GetBlockIDs()
 	}
 
 	box := Conf.Box(boxID)
@@ -290,7 +291,10 @@ func ListDocTree(boxID, path string, sortMode int, flashcard bool, maxListCount
 
 				if flashcard {
 					rootID := strings.TrimSuffix(filepath.Base(parentDocPath), ".sy")
-					if isTreeContainFlashcard(rootID, deckBlockIDs) {
+					newFlashcardCount, dueFlashcardCount, containFlashcard := countTreeFlashcard(rootID)
+					if containFlashcard {
+						doc.NewFlashcardCount = newFlashcardCount
+						doc.DueFlashcardCount = dueFlashcardCount
 						docs = append(docs, doc)
 					}
 				} else {
@@ -310,7 +314,10 @@ func ListDocTree(boxID, path string, sortMode int, flashcard bool, maxListCount
 
 			if flashcard {
 				rootID := strings.TrimSuffix(filepath.Base(file.path), ".sy")
-				if isTreeContainFlashcard(rootID, deckBlockIDs) {
+				newFlashcardCount, dueFlashcardCount, containFlashcard := countTreeFlashcard(rootID)
+				if containFlashcard {
+					doc.NewFlashcardCount = newFlashcardCount
+					doc.DueFlashcardCount = dueFlashcardCount
 					docs = append(docs, doc)
 				}
 			} else {

+ 34 - 7
kernel/model/flashcard.go

@@ -42,34 +42,58 @@ func GetFlashcardNotebooks() (ret []*Box) {
 	if nil == deck {
 		return
 	}
-	deckBlockIDs := deck.GetBlockIDs()
 
 	boxes := Conf.GetOpenedBoxes()
 	for _, box := range boxes {
-		if isBoxContainFlashcard(box.ID, deckBlockIDs) {
+		newFlashcardCount, dueFlashcardCount, containFlashcard := countBoxFlashcard(box.ID)
+		if containFlashcard {
+			box.NewFlashcardCount = newFlashcardCount
+			box.DueFlashcardCount = dueFlashcardCount
 			ret = append(ret, box)
 		}
 	}
 	return
 }
 
-func isTreeContainFlashcard(rootID string, deckBlockIDs []string) (ret bool) {
+func countTreeFlashcard(rootID string) (newFlashcardCount, dueFlashcardCount int, containFlashcard bool) {
+	deck := Decks[builtinDeckID]
+	if nil == deck {
+		return
+	}
+
+	deckBlockIDs := deck.GetBlockIDs()
 	blockIDs := getTreeSubTreeChildBlocks(rootID)
+	containFlashcard = false
 	for _, blockID := range deckBlockIDs {
 		if gulu.Str.Contains(blockID, blockIDs) {
-			return true
+			containFlashcard = true
+			break
 		}
 	}
+	if !containFlashcard {
+		return
+	}
+
+	newFlashCards := deck.GetNewCardsByBlockIDs(blockIDs)
+	newFlashcardCount = len(newFlashCards)
+	newDueFlashcards := deck.GetDueCardsByBlockIDs(blockIDs)
+	dueFlashcardCount = len(newDueFlashcards)
 	return
 }
 
-func isBoxContainFlashcard(boxID string, deckBlockIDs []string) (ret bool) {
+func countBoxFlashcard(boxID string) (newFlashcardCount, dueFlashcardCount int, containFlashcard bool) {
+	deck := Decks[builtinDeckID]
+	if nil == deck {
+		return
+	}
+
 	entries, err := os.ReadDir(filepath.Join(util.DataDir, boxID))
 	if nil != err {
 		logging.LogErrorf("read dir failed: %s", err)
 		return
 	}
 
+	containFlashcard = false
 	for _, entry := range entries {
 		if entry.IsDir() {
 			continue
@@ -80,8 +104,11 @@ func isBoxContainFlashcard(boxID string, deckBlockIDs []string) (ret bool) {
 		}
 
 		rootID := strings.TrimSuffix(entry.Name(), ".sy")
-		if isTreeContainFlashcard(rootID, deckBlockIDs) {
-			return true
+		treeNewFlashcardCount, treeDueFlashcardCount, treeContainFlashcard := countTreeFlashcard(rootID)
+		if treeContainFlashcard {
+			containFlashcard = true
+			newFlashcardCount += treeNewFlashcardCount
+			dueFlashcardCount += treeDueFlashcardCount
 		}
 	}
 	return