forked from st3v3nmw/obsidian-spaced-repetition
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Separate business logic from user interface code (st3v3nmw#751
) * First commit * This doesn't build yet * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Something * Added support for burySiblingCards * Fixed the card count displayed on the status bar * Minor * Minor * Refactoring in preparation for random DeckTreeIter * Support random sequencing of cards during review * Fixed statistics charts * after npm run format * Code for updating question text made resilient to whitespace differences * Added more test cases * Added test case * Fixes for certain cases of whitespace following a question's topic tag * npm run format; update version in manifest.json * Support the Enter key on the numeric keypad in the shortcuts st3v3nmw#706 * In flashcard modal, allow user to click across entire tree item rectangle st3v3nmw#709 * npm run format; temporary filename changes * Updated formatting for lint, file rename * fix issues reported by pnpm lint * Restored version number to "1.10.1" * Restored pnpm-lock.yaml from version 1.10.1 * Updated change log to reference st3v3nmw#706, and st3v3nmw#709 * Fixing capitalization of "Note.ts" (step 1) * Fixing capitalization of "Note.ts" step #2 * Reduced collectCoverageFrom to subset of files with 100% code coverage
- Loading branch information
Showing
53 changed files
with
5,969 additions
and
1,498 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
docs/changelog.md | ||
docs/changelog.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
docs/en/contributing.md | ||
docs/en/contributing.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Question } from "./Question"; | ||
import { CardScheduleInfo } from "./CardSchedule"; | ||
import { CardListType } from "./Deck"; | ||
|
||
export class Card { | ||
question: Question; | ||
cardIdx: number; | ||
|
||
// scheduling | ||
get hasSchedule(): boolean { | ||
return this.scheduleInfo != null; | ||
} | ||
scheduleInfo?: CardScheduleInfo; | ||
|
||
// visuals | ||
front: string; | ||
back: string; | ||
|
||
constructor(init?: Partial<Card>) { | ||
Object.assign(this, init); | ||
} | ||
|
||
get cardListType(): CardListType { | ||
return this.hasSchedule ? CardListType.DueCard : CardListType.NewCard; | ||
} | ||
|
||
get isNew(): boolean { | ||
return !this.hasSchedule; | ||
} | ||
|
||
get isDue(): boolean { | ||
return this.hasSchedule && this.scheduleInfo.isDue(); | ||
} | ||
|
||
formatSchedule(): string { | ||
let result: string = ""; | ||
if (this.hasSchedule) result = this.scheduleInfo.formatSchedule(); | ||
else result = "New"; | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { Moment } from "moment"; | ||
import { | ||
LEGACY_SCHEDULING_EXTRACTOR, | ||
MULTI_SCHEDULING_EXTRACTOR, | ||
TICKS_PER_DAY, | ||
} from "./constants"; | ||
import { INoteEaseList } from "./NoteEaseList"; | ||
import { ReviewResponse, schedule } from "./scheduling"; | ||
import { SRSettings } from "./settings"; | ||
import { formatDate_YYYY_MM_DD } from "./util/utils"; | ||
import { DateUtil, globalDateProvider } from "./util/DateProvider"; | ||
|
||
export class CardScheduleInfo { | ||
dueDate: Moment; | ||
interval: number; | ||
ease: number; | ||
delayBeforeReviewTicks: number; | ||
|
||
constructor(dueDate: Moment, interval: number, ease: number, delayBeforeReviewTicks: number) { | ||
this.dueDate = dueDate; | ||
this.interval = interval; | ||
this.ease = ease; | ||
this.delayBeforeReviewTicks = delayBeforeReviewTicks; | ||
} | ||
|
||
get delayBeforeReviewDaysInt(): number { | ||
return Math.ceil(this.delayBeforeReviewTicks / TICKS_PER_DAY); | ||
} | ||
|
||
isDue(): boolean { | ||
return this.dueDate.isSameOrBefore(globalDateProvider.today); | ||
} | ||
|
||
static getDummySchedule(settings: SRSettings): CardScheduleInfo { | ||
return CardScheduleInfo.fromDueDateStr( | ||
"2000-01-01", | ||
CardScheduleInfo.initialInterval, | ||
settings.baseEase, | ||
0, | ||
); | ||
} | ||
|
||
static fromDueDateStr( | ||
dueDateStr: string, | ||
interval: number, | ||
ease: number, | ||
delayBeforeReviewTicks: number, | ||
) { | ||
const dueDateTicks: Moment = DateUtil.dateStrToMoment(dueDateStr); | ||
return new CardScheduleInfo(dueDateTicks, interval, ease, delayBeforeReviewTicks); | ||
} | ||
|
||
static fromDueDateMoment( | ||
dueDateTicks: Moment, | ||
interval: number, | ||
ease: number, | ||
delayBeforeReviewTicks: number, | ||
) { | ||
return new CardScheduleInfo(dueDateTicks, interval, ease, delayBeforeReviewTicks); | ||
} | ||
|
||
static get initialInterval(): number { | ||
return 1.0; | ||
} | ||
|
||
formatDueDate(): string { | ||
return formatDate_YYYY_MM_DD(this.dueDate); | ||
} | ||
|
||
formatSchedule() { | ||
return `!${this.formatDueDate()},${this.interval},${this.ease}`; | ||
} | ||
} | ||
|
||
export interface ICardScheduleCalculator { | ||
getResetCardSchedule(): CardScheduleInfo; | ||
getNewCardSchedule(response: ReviewResponse, notePath: string): CardScheduleInfo; | ||
calcUpdatedSchedule(response: ReviewResponse, schedule: CardScheduleInfo): CardScheduleInfo; | ||
} | ||
|
||
export class CardScheduleCalculator { | ||
settings: SRSettings; | ||
noteEaseList: INoteEaseList; | ||
dueDatesFlashcards: Record<number, number> = {}; // Record<# of days in future, due count> | ||
|
||
constructor(settings: SRSettings, noteEaseList: INoteEaseList) { | ||
this.settings = settings; | ||
this.noteEaseList = noteEaseList; | ||
} | ||
|
||
getResetCardSchedule(): CardScheduleInfo { | ||
const interval = CardScheduleInfo.initialInterval; | ||
const ease = this.settings.baseEase; | ||
const dueDate = globalDateProvider.today.add(interval, "d"); | ||
const delayBeforeReview = 0; | ||
return CardScheduleInfo.fromDueDateMoment(dueDate, interval, ease, delayBeforeReview); | ||
} | ||
|
||
getNewCardSchedule(response: ReviewResponse, notePath: string): CardScheduleInfo { | ||
const initial_ease: number = this.noteEaseList.getEaseByPath(notePath); | ||
const delayBeforeReview = 0; | ||
|
||
const schedObj: Record<string, number> = schedule( | ||
response, | ||
CardScheduleInfo.initialInterval, | ||
initial_ease, | ||
delayBeforeReview, | ||
this.settings, | ||
this.dueDatesFlashcards, | ||
); | ||
|
||
const interval = schedObj.interval; | ||
const ease = schedObj.ease; | ||
const dueDate = globalDateProvider.today.add(interval, "d"); | ||
return CardScheduleInfo.fromDueDateMoment(dueDate, interval, ease, delayBeforeReview); | ||
} | ||
|
||
calcUpdatedSchedule( | ||
response: ReviewResponse, | ||
cardSchedule: CardScheduleInfo, | ||
): CardScheduleInfo { | ||
const schedObj: Record<string, number> = schedule( | ||
response, | ||
cardSchedule.interval, | ||
cardSchedule.ease, | ||
cardSchedule.delayBeforeReviewTicks, | ||
this.settings, | ||
this.dueDatesFlashcards, | ||
); | ||
const interval = schedObj.interval; | ||
const ease = schedObj.ease; | ||
const dueDate = globalDateProvider.today.add(interval, "d"); | ||
const delayBeforeReview = 0; | ||
return CardScheduleInfo.fromDueDateMoment(dueDate, interval, ease, delayBeforeReview); | ||
} | ||
} | ||
|
||
export class NoteCardScheduleParser { | ||
static createCardScheduleInfoList(questionText: string): CardScheduleInfo[] { | ||
let scheduling: RegExpMatchArray[] = [...questionText.matchAll(MULTI_SCHEDULING_EXTRACTOR)]; | ||
if (scheduling.length === 0) | ||
scheduling = [...questionText.matchAll(LEGACY_SCHEDULING_EXTRACTOR)]; | ||
|
||
const result: CardScheduleInfo[] = []; | ||
for (let i = 0; i < scheduling.length; i++) { | ||
const match: RegExpMatchArray = scheduling[i]; | ||
const dueDateStr = match[1]; | ||
const interval = parseInt(match[2]); | ||
const ease = parseInt(match[3]); | ||
const dueDate: Moment = DateUtil.dateStrToMoment(dueDateStr); | ||
const delayBeforeReviewTicks: number = | ||
dueDate.valueOf() - globalDateProvider.today.valueOf(); | ||
|
||
const info: CardScheduleInfo = new CardScheduleInfo( | ||
dueDate, | ||
interval, | ||
ease, | ||
delayBeforeReviewTicks, | ||
); | ||
result.push(info); | ||
} | ||
return result; | ||
} | ||
|
||
static removeCardScheduleInfo(questionText: string): string { | ||
return questionText.replace(/<!--SR:.+-->/gm, ""); | ||
} | ||
} |
Oops, something went wrong.