diff --git a/rslib/backend.proto b/rslib/backend.proto index 52bb6b24a..848a201b9 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -1082,6 +1082,12 @@ message GraphsIn { } message GraphsOut { + enum Weekday { + SUNDAY = 0; + MONDAY = 1; + FRIDAY = 5; + SATURDAY = 6; + } repeated Card cards = 1; repeated RevlogEntry revlog = 2; uint32 days_elapsed = 3; @@ -1090,6 +1096,7 @@ message GraphsOut { uint32 scheduler_version = 5; /// Seconds to add to UTC timestamps to get local time. int32 local_offset_secs = 7; + Weekday first_weekday = 8; } message RevlogEntry { diff --git a/rslib/src/config.rs b/rslib/src/config.rs index 53838e51c..9a90b1069 100644 --- a/rslib/src/config.rs +++ b/rslib/src/config.rs @@ -18,6 +18,7 @@ pub(crate) fn schema11_config_as_string() -> String { "curDeck": 1, "newSpread": 0, "collapseTime": 1200, + "firstWeekday": 0, "timeLim": 0, "estTimes": true, "dueCounts": true, @@ -47,6 +48,7 @@ pub(crate) enum ConfigKey { ShowRemainingDueCountsInStudy, ShowIntervalsAboveAnswerButtons, NewReviewMix, + FirstWeekday, AnswerTimeLimitSecs, ShowDayLearningCardsFirst, LastUnburiedDay, @@ -75,6 +77,7 @@ impl From for &'static str { ConfigKey::ShowRemainingDueCountsInStudy => "dueCounts", ConfigKey::ShowIntervalsAboveAnswerButtons => "estTimes", ConfigKey::NewReviewMix => "newSpread", + ConfigKey::FirstWeekday => "firstWeekday", ConfigKey::AnswerTimeLimitSecs => "timeLim", ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst", ConfigKey::LastUnburiedDay => "lastUnburied", @@ -227,6 +230,15 @@ impl Collection { self.set_config(ConfigKey::NewReviewMix, &(mix as u8)) } + pub(crate) fn get_first_weekday(&self) -> Weekday { + match self.get_config_default::(ConfigKey::FirstWeekday) { + 1 => Weekday::Monday, + 5 => Weekday::Friday, + 6 => Weekday::Saturday, + _ => Weekday::Sunday, + } + } + pub(crate) fn get_show_due_counts(&self) -> bool { self.get_config_optional(ConfigKey::ShowRemainingDueCountsInStudy) .unwrap_or(true) @@ -309,6 +321,13 @@ pub(crate) enum NewReviewMix { NewFirst = 2, } +pub(crate) enum Weekday { + Sunday = 0, + Monday = 1, + Friday = 5, + Saturday = 6, +} + #[cfg(test)] mod test { use super::SortKind; diff --git a/rslib/src/stats/graphs.rs b/rslib/src/stats/graphs.rs index f0e8e7163..59243e13f 100644 --- a/rslib/src/stats/graphs.rs +++ b/rslib/src/stats/graphs.rs @@ -42,6 +42,7 @@ impl Collection { next_day_at_secs: timing.next_day_at as u32, scheduler_version: self.sched_ver() as u32, local_offset_secs: local_offset_secs as i32, + first_weekday: self.get_first_weekday() as i32, }) } } diff --git a/ts/graphs/calendar.ts b/ts/graphs/calendar.ts index f9e4decfd..a5b1deb23 100644 --- a/ts/graphs/calendar.ts +++ b/ts/graphs/calendar.ts @@ -13,12 +13,21 @@ import { select, mouse } from "d3-selection"; import { scaleLinear, scaleSequential } from "d3-scale"; import { showTooltip, hideTooltip } from "./tooltip"; import { GraphBounds, setDataAvailable, RevlogRange } from "./graph-helpers"; -import { timeDay, timeYear, timeWeek } from "d3-time"; +import { + timeDay, + timeYear, + timeSunday, + timeMonday, + timeFriday, + timeSaturday, +} from "d3-time"; +import type { CountableTimeInterval } from "d3-time"; import type { I18n } from "anki/i18n"; export interface GraphData { // indexed by day, where day is relative to today reviewCount: Map; + timeFunction: CountableTimeInterval; } interface DayDatum { @@ -45,7 +54,16 @@ export function gatherData(data: pb.BackendProto.GraphsOut): GraphData { reviewCount.set(day, count + 1); } - return { reviewCount }; + const timeFunction = + data.firstWeekday === 1 + ? timeMonday + : data.firstWeekday === 5 + ? timeFriday + : data.firstWeekday === 6 + ? timeSaturday + : timeSunday; + + return { reviewCount, timeFunction }; } export function renderCalendar( @@ -73,8 +91,8 @@ export function renderCalendar( if (date.getFullYear() != targetYear) { continue; } - const weekNumber = timeWeek.count(timeYear(date), date); - const weekDay = timeDay.count(timeWeek(date), date); + const weekNumber = sourceData.timeFunction.count(timeYear(date), date); + const weekDay = timeDay.count(sourceData.timeFunction(date), date); const yearDay = timeDay.count(timeYear(date), date); dayMap.set(yearDay, { day, count, weekNumber, weekDay, date } as DayDatum); if (count > maxCount) { @@ -105,8 +123,8 @@ export function renderCalendar( } const yearDay = timeDay.count(timeYear(date), date); if (!dayMap.has(yearDay)) { - const weekNumber = timeWeek.count(timeYear(date), date); - const weekDay = timeDay.count(timeWeek(date), date); + const weekNumber = sourceData.timeFunction.count(timeYear(date), date); + const weekDay = timeDay.count(sourceData.timeFunction(date), date); dayMap.set(yearDay, { day: yearDay, count: 0,