mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
filtered decks w/ scheduling disabled in v3 now log reviews
This commit is contained in:
parent
8830d33826
commit
48c121e4f3
18 changed files with 58 additions and 55 deletions
|
@ -83,7 +83,7 @@ statistics-counts-young-cards = Young
|
||||||
statistics-counts-mature-cards = Mature
|
statistics-counts-mature-cards = Mature
|
||||||
statistics-counts-suspended-cards = Suspended
|
statistics-counts-suspended-cards = Suspended
|
||||||
statistics-counts-buried-cards = Buried
|
statistics-counts-buried-cards = Buried
|
||||||
statistics-counts-early-cards = Early
|
statistics-counts-filtered-cards = Filtered
|
||||||
statistics-counts-learning-cards = Learning
|
statistics-counts-learning-cards = Learning
|
||||||
statistics-counts-relearning-cards = Relearning
|
statistics-counts-relearning-cards = Relearning
|
||||||
statistics-counts-title = Card Counts
|
statistics-counts-title = Card Counts
|
||||||
|
|
|
@ -49,7 +49,8 @@ message RevlogEntry {
|
||||||
LEARNING = 0;
|
LEARNING = 0;
|
||||||
REVIEW = 1;
|
REVIEW = 1;
|
||||||
RELEARNING = 2;
|
RELEARNING = 2;
|
||||||
EARLY_REVIEW = 3;
|
// Recent Anki versions only use this when rescheduling disabled
|
||||||
|
FILTERED = 3;
|
||||||
MANUAL = 4;
|
MANUAL = 4;
|
||||||
}
|
}
|
||||||
int64 id = 1;
|
int64 id = 1;
|
||||||
|
|
|
@ -63,9 +63,11 @@ pub enum RevlogReviewKind {
|
||||||
Learning = 0,
|
Learning = 0,
|
||||||
Review = 1,
|
Review = 1,
|
||||||
Relearning = 2,
|
Relearning = 2,
|
||||||
EarlyReview = 3,
|
/// Old Anki versions called this "Cram" or "Early", and assigned it when
|
||||||
|
/// reviewing cards ahead. It is now only used for filtered decks with
|
||||||
|
/// rescheduling disabled.
|
||||||
|
Filtered = 3,
|
||||||
Manual = 4,
|
Manual = 4,
|
||||||
// Preview = 5,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RevlogReviewKind {
|
impl Default for RevlogReviewKind {
|
||||||
|
|
|
@ -15,19 +15,19 @@ impl CardStateUpdater {
|
||||||
&mut self,
|
&mut self,
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: NewState,
|
next: NewState,
|
||||||
) -> Option<RevlogEntryPartial> {
|
) -> RevlogEntryPartial {
|
||||||
self.card.ctype = CardType::New;
|
self.card.ctype = CardType::New;
|
||||||
self.card.queue = CardQueue::New;
|
self.card.queue = CardQueue::New;
|
||||||
self.card.due = next.position as i32;
|
self.card.due = next.position as i32;
|
||||||
|
|
||||||
RevlogEntryPartial::maybe_new(current, next.into(), 0.0, self.secs_until_rollover())
|
RevlogEntryPartial::new(current, next.into(), 0.0, self.secs_until_rollover())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn apply_learning_state(
|
pub(super) fn apply_learning_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: LearnState,
|
next: LearnState,
|
||||||
) -> Option<RevlogEntryPartial> {
|
) -> RevlogEntryPartial {
|
||||||
self.card.remaining_steps = next.remaining_steps;
|
self.card.remaining_steps = next.remaining_steps;
|
||||||
self.card.ctype = CardType::Learn;
|
self.card.ctype = CardType::Learn;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ impl CardStateUpdater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RevlogEntryPartial::maybe_new(current, next.into(), 0.0, self.secs_until_rollover())
|
RevlogEntryPartial::new(current, next.into(), 0.0, self.secs_until_rollover())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds secs + fuzz to current time
|
/// Adds secs + fuzz to current time
|
||||||
|
|
|
@ -42,8 +42,6 @@ pub struct CardAnswer {
|
||||||
pub milliseconds_taken: u32,
|
pub milliseconds_taken: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// fixme: log preview review
|
|
||||||
|
|
||||||
/// Holds the information required to determine a given card's
|
/// Holds the information required to determine a given card's
|
||||||
/// current state, and to apply a state change to it.
|
/// current state, and to apply a state change to it.
|
||||||
struct CardStateUpdater {
|
struct CardStateUpdater {
|
||||||
|
@ -103,7 +101,7 @@ impl CardStateUpdater {
|
||||||
&mut self,
|
&mut self,
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: CardState,
|
next: CardState,
|
||||||
) -> Result<Option<RevlogEntryPartial>> {
|
) -> Result<RevlogEntryPartial> {
|
||||||
let revlog = match next {
|
let revlog = match next {
|
||||||
CardState::Normal(normal) => {
|
CardState::Normal(normal) => {
|
||||||
// transitioning from filtered state?
|
// transitioning from filtered state?
|
||||||
|
@ -141,7 +139,7 @@ impl CardStateUpdater {
|
||||||
&mut self,
|
&mut self,
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: NormalState,
|
next: NormalState,
|
||||||
) -> Option<RevlogEntryPartial> {
|
) -> RevlogEntryPartial {
|
||||||
self.card.reps += 1;
|
self.card.reps += 1;
|
||||||
self.card.original_due = 0;
|
self.card.original_due = 0;
|
||||||
|
|
||||||
|
@ -259,9 +257,9 @@ impl Collection {
|
||||||
current_state, answer.current_state,
|
current_state, answer.current_state,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
if let Some(revlog_partial) = updater.apply_study_state(current_state, answer.new_state)? {
|
let revlog_partial = updater.apply_study_state(current_state, answer.new_state)?;
|
||||||
self.add_partial_revlog(revlog_partial, usn, answer)?;
|
self.add_partial_revlog(revlog_partial, usn, answer)?;
|
||||||
}
|
|
||||||
self.update_deck_stats_from_answer(usn, answer, &updater, original.queue)?;
|
self.update_deck_stats_from_answer(usn, answer, &updater, original.queue)?;
|
||||||
self.maybe_bury_siblings(&original, &updater.config)?;
|
self.maybe_bury_siblings(&original, &updater.config)?;
|
||||||
let timing = updater.timing;
|
let timing = updater.timing;
|
||||||
|
|
|
@ -9,17 +9,16 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
impl CardStateUpdater {
|
impl CardStateUpdater {
|
||||||
// fixme: check learning card moved into preview
|
|
||||||
// restores correctly in both learn and day-learn case
|
|
||||||
pub(super) fn apply_preview_state(
|
pub(super) fn apply_preview_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: PreviewState,
|
next: PreviewState,
|
||||||
) -> Option<RevlogEntryPartial> {
|
) -> RevlogEntryPartial {
|
||||||
|
let revlog = RevlogEntryPartial::new(current, next.into(), 0.0, self.secs_until_rollover());
|
||||||
if next.finished {
|
if next.finished {
|
||||||
self.card
|
self.card
|
||||||
.remove_from_filtered_deck_restoring_queue(SchedulerVersion::V2);
|
.remove_from_filtered_deck_restoring_queue(SchedulerVersion::V2);
|
||||||
return None;
|
return revlog;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.card.queue = CardQueue::PreviewRepeat;
|
self.card.queue = CardQueue::PreviewRepeat;
|
||||||
|
@ -34,7 +33,7 @@ impl CardStateUpdater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RevlogEntryPartial::maybe_new(current, next.into(), 0.0, self.secs_until_rollover())
|
revlog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ impl CardStateUpdater {
|
||||||
&mut self,
|
&mut self,
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: RelearnState,
|
next: RelearnState,
|
||||||
) -> Option<RevlogEntryPartial> {
|
) -> RevlogEntryPartial {
|
||||||
self.card.interval = next.review.scheduled_days;
|
self.card.interval = next.review.scheduled_days;
|
||||||
self.card.remaining_steps = next.learning.remaining_steps;
|
self.card.remaining_steps = next.learning.remaining_steps;
|
||||||
self.card.ctype = CardType::Relearn;
|
self.card.ctype = CardType::Relearn;
|
||||||
|
@ -33,7 +33,7 @@ impl CardStateUpdater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RevlogEntryPartial::maybe_new(
|
RevlogEntryPartial::new(
|
||||||
current,
|
current,
|
||||||
next.into(),
|
next.into(),
|
||||||
next.review.ease_factor,
|
next.review.ease_factor,
|
||||||
|
|
|
@ -12,7 +12,7 @@ impl CardStateUpdater {
|
||||||
&mut self,
|
&mut self,
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: ReviewState,
|
next: ReviewState,
|
||||||
) -> Option<RevlogEntryPartial> {
|
) -> RevlogEntryPartial {
|
||||||
self.card.queue = CardQueue::Review;
|
self.card.queue = CardQueue::Review;
|
||||||
self.card.ctype = CardType::Review;
|
self.card.ctype = CardType::Review;
|
||||||
self.card.interval = next.scheduled_days;
|
self.card.interval = next.scheduled_days;
|
||||||
|
@ -21,7 +21,7 @@ impl CardStateUpdater {
|
||||||
self.card.lapses = next.lapses;
|
self.card.lapses = next.lapses;
|
||||||
self.card.remaining_steps = 0;
|
self.card.remaining_steps = 0;
|
||||||
|
|
||||||
RevlogEntryPartial::maybe_new(
|
RevlogEntryPartial::new(
|
||||||
current,
|
current,
|
||||||
next.into(),
|
next.into(),
|
||||||
next.ease_factor,
|
next.ease_factor,
|
||||||
|
|
|
@ -15,14 +15,12 @@ pub struct RevlogEntryPartial {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RevlogEntryPartial {
|
impl RevlogEntryPartial {
|
||||||
/// Returns None in the Preview case, since preview cards do not currently log.
|
pub(super) fn new(
|
||||||
pub(super) fn maybe_new(
|
|
||||||
current: CardState,
|
current: CardState,
|
||||||
next: CardState,
|
next: CardState,
|
||||||
ease_factor: f32,
|
ease_factor: f32,
|
||||||
secs_until_rollover: u32,
|
secs_until_rollover: u32,
|
||||||
) -> Option<Self> {
|
) -> Self {
|
||||||
current.revlog_kind().map(|review_kind| {
|
|
||||||
let next_interval = next.interval_kind().maybe_as_days(secs_until_rollover);
|
let next_interval = next.interval_kind().maybe_as_days(secs_until_rollover);
|
||||||
let current_interval = current.interval_kind().maybe_as_days(secs_until_rollover);
|
let current_interval = current.interval_kind().maybe_as_days(secs_until_rollover);
|
||||||
|
|
||||||
|
@ -30,9 +28,8 @@ impl RevlogEntryPartial {
|
||||||
interval: next_interval,
|
interval: next_interval,
|
||||||
last_interval: current_interval,
|
last_interval: current_interval,
|
||||||
ease_factor,
|
ease_factor,
|
||||||
review_kind,
|
review_kind: current.revlog_kind(),
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn into_revlog_entry(
|
pub(super) fn into_revlog_entry(
|
||||||
|
|
|
@ -20,10 +20,10 @@ impl FilteredState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn revlog_kind(self) -> Option<RevlogReviewKind> {
|
pub(crate) fn revlog_kind(self) -> RevlogReviewKind {
|
||||||
match self {
|
match self {
|
||||||
FilteredState::Preview(_state) => None,
|
FilteredState::Preview(state) => state.revlog_kind(),
|
||||||
FilteredState::Rescheduling(state) => Some(state.revlog_kind()),
|
FilteredState::Rescheduling(state) => state.revlog_kind(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,9 @@ impl CardState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn revlog_kind(self) -> Option<RevlogReviewKind> {
|
pub(crate) fn revlog_kind(self) -> RevlogReviewKind {
|
||||||
match self {
|
match self {
|
||||||
CardState::Normal(normal) => Some(normal.revlog_kind()),
|
CardState::Normal(normal) => normal.revlog_kind(),
|
||||||
CardState::Filtered(filtered) => filtered.revlog_kind(),
|
CardState::Filtered(filtered) => filtered.revlog_kind(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::{IntervalKind, NextCardStates, StateContext};
|
use super::{IntervalKind, NextCardStates, StateContext};
|
||||||
|
use crate::revlog::RevlogReviewKind;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct PreviewState {
|
pub struct PreviewState {
|
||||||
|
@ -14,6 +15,10 @@ impl PreviewState {
|
||||||
IntervalKind::InSecs(self.scheduled_secs)
|
IntervalKind::InSecs(self.scheduled_secs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn revlog_kind(self) -> RevlogReviewKind {
|
||||||
|
RevlogReviewKind::Filtered
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn next_states(self, ctx: &StateContext) -> NextCardStates {
|
pub(crate) fn next_states(self, ctx: &StateContext) -> NextCardStates {
|
||||||
NextCardStates {
|
NextCardStates {
|
||||||
current: self.into(),
|
current: self.into(),
|
||||||
|
|
|
@ -46,7 +46,7 @@ impl ReviewState {
|
||||||
|
|
||||||
pub(crate) fn revlog_kind(self) -> RevlogReviewKind {
|
pub(crate) fn revlog_kind(self) -> RevlogReviewKind {
|
||||||
if self.days_late() < 0 {
|
if self.days_late() < 0 {
|
||||||
RevlogReviewKind::EarlyReview
|
RevlogReviewKind::Filtered
|
||||||
} else {
|
} else {
|
||||||
RevlogReviewKind::Review
|
RevlogReviewKind::Review
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,14 +213,14 @@ fn revlog_to_text(e: RevlogEntry, tr: &I18n) -> RevlogText {
|
||||||
RevlogReviewKind::Learning => tr.card_stats_review_log_type_learn().into(),
|
RevlogReviewKind::Learning => tr.card_stats_review_log_type_learn().into(),
|
||||||
RevlogReviewKind::Review => tr.card_stats_review_log_type_review().into(),
|
RevlogReviewKind::Review => tr.card_stats_review_log_type_review().into(),
|
||||||
RevlogReviewKind::Relearning => tr.card_stats_review_log_type_relearn().into(),
|
RevlogReviewKind::Relearning => tr.card_stats_review_log_type_relearn().into(),
|
||||||
RevlogReviewKind::EarlyReview => tr.card_stats_review_log_type_filtered().into(),
|
RevlogReviewKind::Filtered => tr.card_stats_review_log_type_filtered().into(),
|
||||||
RevlogReviewKind::Manual => tr.card_stats_review_log_type_manual().into(),
|
RevlogReviewKind::Manual => tr.card_stats_review_log_type_manual().into(),
|
||||||
};
|
};
|
||||||
let kind_class = match e.review_kind {
|
let kind_class = match e.review_kind {
|
||||||
RevlogReviewKind::Learning => String::from("revlog-learn"),
|
RevlogReviewKind::Learning => String::from("revlog-learn"),
|
||||||
RevlogReviewKind::Review => String::from("revlog-review"),
|
RevlogReviewKind::Review => String::from("revlog-review"),
|
||||||
RevlogReviewKind::Relearning => String::from("revlog-relearn"),
|
RevlogReviewKind::Relearning => String::from("revlog-relearn"),
|
||||||
RevlogReviewKind::EarlyReview => String::from("revlog-filtered"),
|
RevlogReviewKind::Filtered => String::from("revlog-filtered"),
|
||||||
RevlogReviewKind::Manual => String::from("revlog-manual"),
|
RevlogReviewKind::Manual => String::from("revlog-manual"),
|
||||||
};
|
};
|
||||||
let rating = e.button_chosen.to_string();
|
let rating = e.button_chosen.to_string();
|
||||||
|
|
|
@ -65,13 +65,14 @@ export function gatherData(data: Stats.GraphsResponse, range: GraphRange): Graph
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ReviewKind.REVIEW:
|
case ReviewKind.REVIEW:
|
||||||
case ReviewKind.EARLY_REVIEW:
|
|
||||||
if (review.lastInterval < 21) {
|
if (review.lastInterval < 21) {
|
||||||
buttons = young;
|
buttons = young;
|
||||||
} else {
|
} else {
|
||||||
buttons = mature;
|
buttons = mature;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ReviewKind.FILTERED:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons[buttonNum - 1] += 1;
|
buttons[buttonNum - 1] += 1;
|
||||||
|
|
|
@ -51,7 +51,7 @@ function gatherData(data: Stats.GraphsResponse, range: GraphRange): Hour[] {
|
||||||
case ReviewKind.REVIEW:
|
case ReviewKind.REVIEW:
|
||||||
case ReviewKind.RELEARNING:
|
case ReviewKind.RELEARNING:
|
||||||
break; // from switch
|
break; // from switch
|
||||||
case ReviewKind.EARLY_REVIEW:
|
case ReviewKind.FILTERED:
|
||||||
case ReviewKind.MANUAL:
|
case ReviewKind.MANUAL:
|
||||||
continue; // next loop iteration
|
continue; // next loop iteration
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ interface Reviews {
|
||||||
relearn: number;
|
relearn: number;
|
||||||
young: number;
|
young: number;
|
||||||
mature: number;
|
mature: number;
|
||||||
early: number;
|
filtered: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphData {
|
export interface GraphData {
|
||||||
|
@ -56,7 +56,7 @@ type BinType = Bin<Map<number, Reviews[]>, number>;
|
||||||
export function gatherData(data: Stats.GraphsResponse): GraphData {
|
export function gatherData(data: Stats.GraphsResponse): GraphData {
|
||||||
const reviewCount = new Map<number, Reviews>();
|
const reviewCount = new Map<number, Reviews>();
|
||||||
const reviewTime = new Map<number, Reviews>();
|
const reviewTime = new Map<number, Reviews>();
|
||||||
const empty = { mature: 0, young: 0, learn: 0, relearn: 0, early: 0 };
|
const empty = { mature: 0, young: 0, learn: 0, relearn: 0, filtered: 0 };
|
||||||
|
|
||||||
for (const review of data.revlog as Stats.RevlogEntry[]) {
|
for (const review of data.revlog as Stats.RevlogEntry[]) {
|
||||||
if (review.reviewKind == ReviewKind.MANUAL) {
|
if (review.reviewKind == ReviewKind.MANUAL) {
|
||||||
|
@ -89,9 +89,9 @@ export function gatherData(data: Stats.GraphsResponse): GraphData {
|
||||||
timeEntry.mature += review.takenMillis;
|
timeEntry.mature += review.takenMillis;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ReviewKind.EARLY_REVIEW:
|
case ReviewKind.FILTERED:
|
||||||
countEntry.early += 1;
|
countEntry.filtered += 1;
|
||||||
timeEntry.early += review.takenMillis;
|
timeEntry.filtered += review.takenMillis;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ function totalsForBin(bin: BinType): number[] {
|
||||||
total[1] += entry[1].relearn;
|
total[1] += entry[1].relearn;
|
||||||
total[2] += entry[1].young;
|
total[2] += entry[1].young;
|
||||||
total[3] += entry[1].mature;
|
total[3] += entry[1].mature;
|
||||||
total[4] += entry[1].early;
|
total[4] += entry[1].filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
|
@ -246,7 +246,7 @@ export function renderReviews(
|
||||||
[reds(1), tr.statisticsCountsRelearningCards(), valueLabel(totals[1])],
|
[reds(1), tr.statisticsCountsRelearningCards(), valueLabel(totals[1])],
|
||||||
[lighterGreens(1), tr.statisticsCountsYoungCards(), valueLabel(totals[2])],
|
[lighterGreens(1), tr.statisticsCountsYoungCards(), valueLabel(totals[2])],
|
||||||
[darkerGreens(1), tr.statisticsCountsMatureCards(), valueLabel(totals[3])],
|
[darkerGreens(1), tr.statisticsCountsMatureCards(), valueLabel(totals[3])],
|
||||||
[purples(1), tr.statisticsCountsEarlyCards(), valueLabel(totals[4])],
|
[purples(1), tr.statisticsCountsFilteredCards(), valueLabel(totals[4])],
|
||||||
["transparent", tr.statisticsRunningTotal(), valueLabel(cumulative)],
|
["transparent", tr.statisticsRunningTotal(), valueLabel(cumulative)],
|
||||||
];
|
];
|
||||||
for (const [colour, label, detail] of lines) {
|
for (const [colour, label, detail] of lines) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ export function gatherData(data: Stats.GraphsResponse): TodayData {
|
||||||
case ReviewKind.RELEARNING:
|
case ReviewKind.RELEARNING:
|
||||||
relearnCount += 1;
|
relearnCount += 1;
|
||||||
break;
|
break;
|
||||||
case ReviewKind.EARLY_REVIEW:
|
case ReviewKind.FILTERED:
|
||||||
earlyReviewCount += 1;
|
earlyReviewCount += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue