Skip to content

Commit

Permalink
Add statistics
Browse files Browse the repository at this point in the history
  • Loading branch information
linanwx committed Jun 25, 2023
1 parent fd6b96f commit 4b0ca3c
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 86 deletions.
89 changes: 66 additions & 23 deletions arrangement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,50 @@ import i18next from "i18next"
import { Pattern } from "Pattern"

class ArrangementItem {
Name:string
Name: string
Count: number
Display: string
constructor(name:string, count:number, display:string) {
constructor(name: string, count: number, display: string) {
this.Name = name
this.Count = count
this.Display = display
}
}

const NEWTAG = "new"
const REVIEWTAG = "review"
const LEARNTAG = "learn"

export class Stats {
NewCount: number
ReviewCount: number
LearnCount: number
}

export class PatternIter {
pattern: Pattern
index: number
total: number
constructor(pattern:Pattern,index:number,total:number) {
constructor(pattern: Pattern, index: number, total: number) {
this.pattern = pattern
this.index = index
this.total = total
}
}

abstract class ArrangementBase {
abstract PatternSequence(Name:string):AsyncGenerator<PatternIter, boolean, unknown>
abstract ArrangementList():ArrangementItem[]
abstract PatternSequence(Name: string): AsyncGenerator<PatternIter, boolean, unknown>
abstract ArrangementList(): ArrangementItem[]
abstract stats(): Stats
}

export class Arrangement implements ArrangementBase{
function isToday(date: moment.Moment): boolean {
const todayStart = window.moment().startOf('day')
const todayEnd = window.moment().endOf('day')
return date.isBetween(todayStart, todayEnd, null, '[]');
}

export class Arrangement implements ArrangementBase {
private allPattern: Pattern[]
private newPattern: Pattern[]
private needReviewPattern: Pattern[]
Expand All @@ -44,7 +61,7 @@ export class Arrangement implements ArrangementBase{
}
async init() {
let search = NewCardSearch()
let allcards = await search.search()
let allcards = await search.search()
this.allPattern = []
this.newPattern = []
this.needReviewPattern = []
Expand All @@ -56,16 +73,42 @@ export class Arrangement implements ArrangementBase{
}
this.sort()
}
stats(): Stats {
let newCount = 0
let reviewCount = 0
let learnCount = 0
for (let p of this.allPattern) {
if (p.schedule.Last && p.schedule.Last != "") {
if (isToday(p.schedule.LastTime)) {
if (p.schedule.Opts.length == 1) {
newCount++
} else {
reviewCount++
}
}
}
if (p.schedule.Learned && p.schedule.Learned != "") {
if (isToday(p.schedule.LearnedTime)) {
learnCount++
}
}
}
let stats = new Stats
stats.LearnCount = learnCount
stats.NewCount = newCount
stats.ReviewCount = reviewCount
return stats
}
ArrangementList(): ArrangementItem[] {
let retlist:ArrangementItem[] = []
let retlist: ArrangementItem[] = []
if (this.newPattern.length > 0) {
retlist.push(new ArrangementItem("new", this.newPattern.length, i18next.t('StartTextNew')))
retlist.push(new ArrangementItem(NEWTAG, this.newPattern.length, i18next.t('StartTextNew')))
}
if (this.needReviewPattern.length > 0 ) {
retlist.push(new ArrangementItem("review", this.needReviewPattern.length, i18next.t('StartTextReview')))
if (this.needReviewPattern.length > 0) {
retlist.push(new ArrangementItem(REVIEWTAG, this.needReviewPattern.length, i18next.t('StartTextReview')))
}
if (this.needLearn.length > 0 ) {
retlist.push(new ArrangementItem("learn", this.needLearn.length, i18next.t('StartTextLearn')))
if (this.needLearn.length > 0) {
retlist.push(new ArrangementItem(LEARNTAG, this.needLearn.length, i18next.t('StartTextLearn')))
}
return retlist
}
Expand All @@ -85,13 +128,13 @@ export class Arrangement implements ArrangementBase{
this.needLearn.push(p)
}
}
this.newPattern.sort(()=>{
this.newPattern.sort(() => {
return .5 - Math.random()
})
this.needReviewPattern.sort(()=>{
this.needReviewPattern.sort(() => {
return .5 - Math.random()
})
this.needLearn.sort((a,b)=>{
this.needLearn.sort((a, b) => {
if (a.schedule.LearnedTime.isAfter(b.schedule.LearnedTime)) {
return 1
}
Expand All @@ -113,27 +156,27 @@ export class Arrangement implements ArrangementBase{
}
return
}
async *PatternSequence(name:string) {
if (name == "review") {
for (let i=0;i<this.needReviewPattern.length;i++) {
async *PatternSequence(name: string) {
if (name == REVIEWTAG) {
for (let i = 0; i < this.needReviewPattern.length; i++) {
let p = this.needReviewPattern[i]
let cardp = await this.findLivePattern(p)
if (cardp) {
yield new PatternIter(cardp, i, this.needReviewPattern.length)
}
}
}
if (name == "new") {
for (let i=0;i<this.newPattern.length;i++) {
if (name == NEWTAG) {
for (let i = 0; i < this.newPattern.length; i++) {
let p = this.newPattern[i]
let cardp = await this.findLivePattern(p)
if (cardp) {
yield new PatternIter(cardp, i, this.newPattern.length)
}
}
}
if (name == "learn") {
for (let i=0;i<this.needLearn.length;i++) {
if (name == LEARNTAG) {
for (let i = 0; i < this.needLearn.length; i++) {
let p = this.needLearn[i]
let cardp = await this.findLivePattern(p)
if (cardp) {
Expand Down
77 changes: 75 additions & 2 deletions language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ const zhTranslation = {
SettingTextWaittingDesc: "等待超时有两个目的:1)在等待期间,它迫使你花时间复习、思考和记忆。2)更重要的是,它可以帮助您更准确地区分选项。你会发现,当你对答案有了一些想法时,如果你选择了错误的选项,你的惩罚时间会变得很长。因此,你更有可能选择合适的选项,而不是随机评估问题,因为这种评估非常不准确。例如,当您对答案不确定时,最好选择“不确定”选项。否则,如果你选择了“已知”选项,但答案是错误的,等待时间将会很长。您可以根据自己的情况调整此选项以延长或缩短等待超时的持续时间,也可以完全关闭等待。\n等待超时的推荐设置值,应该是您在三个小时内记住一个六个字母的单词并不忘记它的秒数。"
}

export function addTranslation(key: string, translations: any) {
const languages = ['en', 'zh', 'ja', 'zh-TW', 'ko', 'ar', 'pt', 'de', 'ru', 'fr', 'es', 'it', 'id', 'ro', 'cs', 'no', 'pl', 'uk', 'sq', 'th', 'fa', 'tr', 'nl', 'ms', 'pt-BR', 'am', 'da'];
languages.forEach(lang => {
if (translations[lang]) {
i18n.addResourceBundle(lang, 'translation', {
[key]: translations[lang],
}, true, true);
}
});
}

export function initLanguage() {
i18n.use(initReactI18next).init(
{
Expand Down Expand Up @@ -146,10 +157,10 @@ export function initLanguage() {
'pt-BR': {
translation: ptBRTranslation
},
am:{
am: {
translation: amTranslation
},
da:{
da: {
translation: daTranslation
}
},
Expand All @@ -160,6 +171,8 @@ export function initLanguage() {
},
}
)
addTranslation("TodayStats", todayStatic)
addTranslation("StartReview", StartReview)
const lang = window.localStorage.getItem('language') || "en"
i18n.changeLanguage(lang).catch(err => {
console.error('Failed to change language:', err);
Expand Down Expand Up @@ -993,4 +1006,64 @@ const ptBRTranslation = {
SettingTextHardChoiceDesc: "Quando você escolhe uma opção difícil, antecipa o próximo tempo de revisão. Um valor maior resulta em uma revisão anterior. Recomendado: 1.",
SettingTextWaitting: "Tempo Limite de Espera",
SettingTextWaittingDesc: "O tempo limite de espera tem dois propósitos: 1) Durante o período de espera, ele te obriga a dedicar tempo à revisão, contemplação e memorização. 2) Mais importante, ele ajuda você a distinguir opções com mais precisão. Você vai perceber que quando tiver alguma ideia sobre a resposta, se escolher a opção errada, seu tempo de penalidade se torna mais longo. Portanto, você tem mais probabilidade de escolher a opção apropriada em vez de adivinhar aleatoriamente a questão, já que essa adivinhação é altamente imprecisa. Por exemplo, quando você não tem certeza sobre a resposta, é melhor escolher a opção 'Não Tenho Certeza'. Caso contrário, se escolher a opção 'Eu Sei', mas a resposta estiver errada, o tempo de espera será longo. Você pode ajustar essa opção com base na sua própria situação para estender ou encurtar a duração do tempo limite de espera, ou pode desabilitá-lo completamente. Os valores recomendados para o tempo limite de espera devem ser o número de segundos necessários para você lembrar uma palavra de seis letras dentro de três horas sem esquecê-la."
}

const todayStatic = {
"en": "Today's Learning Progress Statistics",
"zh": "今日学习进度统计",
"ja": "今日の学習進度統計",
"zh-TW": "今日學習進度統計",
"ko": "오늘의 학습 진행 상황 통계",
"ar": "إحصائيات تقدم التعلم اليوم",
"pt": "Estatísticas de Progresso de Aprendizado de Hoje",
"de": "Statistiken zum Lernfortschritt von heute",
"ru": "Статистика учебного прогресса на сегодня",
"fr": "Statistiques d'avancement des apprentissages du jour",
"es": "Estadísticas del Progreso de Aprendizaje de Hoy",
"it": "Statistiche del progresso di apprendimento di oggi",
"id": "Statistik Kemajuan Belajar Hari Ini",
"ro": "Statisticile de progres al învățării de astăzi",
"cs": "Dnešní statistiky učebního pokroku",
"no": "Dagens statistikk for læringsfremgang",
"pl": "Dzisiejsze statystyki postępów w nauce",
"uk": "Статистика навчального прогресу на сьогодні",
"sq": "Statistikat e Progresit të Mësimit të Sotëm",
"th": "สถิติความคืบหน้าในการเรียนรู้วันนี้",
"fa": "آمار پیشرفت آموزش امروز",
"tr": "Bugünkü Öğrenme İlerleme İstatistikleri",
"nl": "Statistieken van de leerprogressie van vandaag",
"ms": "Statistik Kemajuan Pembelajaran Hari Ini",
"pt-BR": "Estatísticas de Progresso de Aprendizado de Hoje",
"am": "የዛሬ የትምህርት እርስዎ ግብር ሪፖርት",
"da": "Dagens statistik for læringens fremgang"
}

const StartReview = {
"en": "Start Reviewing",
"zh": "开始复习",
"ja": "復習を始める",
"zh-TW": "開始複習",
"ko": "복습 시작하기",
"ar": "ابدأ المراجعة",
"pt": "Iniciar Revisão",
"de": "Mit dem Review beginnen",
"ru": "Начать повторение",
"fr": "Commencer la révision",
"es": "Comenzar a revisar",
"it": "Inizia la revisione",
"id": "Mulai Meninjau",
"ro": "Începeți revizuirea",
"cs": "Začít opakování",
"no": "Start gjennomgangen",
"pl": "Rozpocznij powtórkę",
"uk": "Почати повторення",
"sq": "Fillo rishikimin",
"th": "เริ่มการทบทวน",
"fa": "شروع مرور",
"tr": "İncelemeye Başla",
"nl": "Begin met herziening",
"ms": "Mula Menyemak Semula",
"pt-BR": "Iniciar Revisão",
"am": "መሰረታውን ጀምር",
"da": "Start med at gennemgå"
}
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "aosr",
"name": "Aosr",
"version": "1.0.33",
"version": "1.0.34",
"minAppVersion": "0.12.0",
"description": "Another obsidian spaced repetition",
"author": "linanwx",
Expand Down
37 changes: 26 additions & 11 deletions schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export interface PatternYaml {
Opts: string
// 上次被标记为忘记,最后一次复习的时间
Learned: string | null
// 上次被标记为忘记,之后复习的次数
// 上次被标记为忘记,之后复习的进度 默认为0 范围从-2到+2
LearnedCount: number | null
// 用于读取存储的schedule yaml格式 需要复制对象
copy(v: PatternYaml): void
Expand Down Expand Up @@ -185,33 +185,48 @@ export class defaultSchedule implements PatternSchedule {
} else if (this.Opts.at(-1) == String(ReviewEnum.FAIR)) {
} else if (this.LearnedCount && this.LearnedCount >= 2) {
} else {
// 中期记忆内的信息不需要学习
// 这部分内容会在过了中期记忆从记忆区中清空后重新安排学习
let checkPoint = window.moment().add(-3, "hours")
if (this.LearnedTime.isAfter(checkPoint)) {
info.IsWait = true
} else {
if (this.LearnedCount == null) {
// 标记为HARD和FORGET后
// 没有学习记录立即复习一次
info.IsLearn = true
} else {
let checkPoint: moment.Moment
if (this.LearnedCount <= -2) {
checkPoint = window.moment().add(-10, "minutes")
} else if (this.LearnedCount <= -1) {
checkPoint = window.moment().add(-1, "hours")
} else if (this.LearnedCount <= 0) {
checkPoint = window.moment().add(-3, "hours")
} else if (this.LearnedCount <= 1) {
checkPoint = window.moment().add(-12, "hours")
} else {
checkPoint = window.moment().add(-36, "hours")
}
if (this.LearnedTime.isAfter(checkPoint)) {
info.IsWait = true
} else {
info.IsLearn = true
}
}
}
return info
}
private getLearnResult(opt: LearnEnum) {
let learnCount = 0
let learnCount = -2
if (this.LearnedCount) {
learnCount = this.LearnedCount
}
if (opt == LearnEnum.FAIR) {
learnCount++
learnCount += 1
}
if (opt == LearnEnum.HARD) {
learnCount--
learnCount -= 1
}
if (opt == LearnEnum.FORGET) {
learnCount -= 2
}
if (opt == LearnEnum.EASY) {
learnCount += 2
learnCount += 1.5
}
learnCount = Math.max(-2, learnCount)
learnCount = Math.min(2, learnCount)
Expand Down
15 changes: 8 additions & 7 deletions tag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class emojiplugin implements PluginValue {
this.decorations = this.buildDecorations(view);
}
update(update: ViewUpdate) {
if (update.docChanged || update.viewportChanged || update.selectionSet) {
if (update.docChanged || update.viewportChanged || update.selectionSet || update.heightChanged) {
this.decorations = this.buildDecorations(update.view);
}
}
Expand All @@ -39,16 +39,17 @@ export class emojiplugin implements PluginValue {
buildDecorations(view: EditorView): DecorationSet {
const builder = new RangeSetBuilder<Decoration>();
const docText = view.state.doc.toString();

for (let { from, to } of view.visibleRanges) {
syntaxTree(view.state).iterate({
let tree = syntaxTree(view.state)
if (tree === null) {
continue
}
tree.iterate({
from,
to,
enter(node) {
view.visibleRanges
let text = docText.substring(node.from, node.to)
// console.log(`name: ${node.name}, text: ${text}`)
if (node.name.startsWith("hashtag")) {
if (node.name.startsWith("hashtag") && node.name.contains("AOSR")) {
let text = docText.substring(node.from, node.to)
if (text.startsWith("AOSR/")) {
if (!inSelection(view.state.selection, node.from, node.to)) {
builder.add(
Expand Down
Loading

0 comments on commit 4b0ca3c

Please sign in to comment.