mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
89 lines
3.3 KiB
Rust
89 lines
3.3 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
use std::collections::HashMap;
|
|
|
|
use anki_proto::stats::graphs_response::true_retention_stats::TrueRetention;
|
|
use anki_proto::stats::graphs_response::TrueRetentionStats;
|
|
|
|
use super::GraphsContext;
|
|
use super::TimestampSecs;
|
|
use crate::revlog::RevlogReviewKind;
|
|
|
|
impl GraphsContext {
|
|
pub fn calculate_true_retention(&self) -> TrueRetentionStats {
|
|
let mut stats = TrueRetentionStats::default();
|
|
|
|
// create periods
|
|
let day = 86400;
|
|
let periods = vec![
|
|
(
|
|
"today",
|
|
self.next_day_start.adding_secs(-day),
|
|
self.next_day_start,
|
|
),
|
|
(
|
|
"yesterday",
|
|
self.next_day_start.adding_secs(-2 * day),
|
|
self.next_day_start.adding_secs(-day),
|
|
),
|
|
(
|
|
"week",
|
|
self.next_day_start.adding_secs(-7 * day),
|
|
self.next_day_start,
|
|
),
|
|
(
|
|
"month",
|
|
self.next_day_start.adding_secs(-30 * day),
|
|
self.next_day_start,
|
|
),
|
|
(
|
|
"year",
|
|
self.next_day_start.adding_secs(-365 * day),
|
|
self.next_day_start,
|
|
),
|
|
("all_time", TimestampSecs(0), self.next_day_start),
|
|
];
|
|
|
|
// create period stats
|
|
let mut period_stats: HashMap<&str, TrueRetention> = periods
|
|
.iter()
|
|
.map(|(name, _, _)| (*name, TrueRetention::default()))
|
|
.collect();
|
|
|
|
self.revlog
|
|
.iter()
|
|
.filter(|review| {
|
|
// not manually rescheduled
|
|
review.button_chosen > 0
|
|
// not cramming
|
|
&& (review.review_kind != RevlogReviewKind::Filtered || review.ease_factor != 0)
|
|
// cards with an interval ≥ 1 day
|
|
&& (review.review_kind == RevlogReviewKind::Review
|
|
|| review.last_interval <= -86400
|
|
|| review.last_interval >= 1)
|
|
})
|
|
.for_each(|review| {
|
|
for (period_name, start, end) in &periods {
|
|
if review.id.as_secs() >= *start && review.id.as_secs() < *end {
|
|
let period_stat = period_stats.get_mut(period_name).unwrap();
|
|
const MATURE_IVL: i32 = 21; // mature interval is 21 days
|
|
match (review.last_interval < MATURE_IVL, review.button_chosen) {
|
|
(true, 1) => period_stat.young_failed += 1,
|
|
(true, _) => period_stat.young_passed += 1,
|
|
(false, 1) => period_stat.mature_failed += 1,
|
|
(false, _) => period_stat.mature_passed += 1,
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
stats.today = Some(period_stats["today"]);
|
|
stats.yesterday = Some(period_stats["yesterday"]);
|
|
stats.week = Some(period_stats["week"]);
|
|
stats.month = Some(period_stats["month"]);
|
|
stats.year = Some(period_stats["year"]);
|
|
stats.all_time = Some(period_stats["all_time"]);
|
|
|
|
stats
|
|
}
|
|
}
|