i18n card counts

This commit is contained in:
Damien Elmes 2020-06-27 21:10:17 +10:00
parent 01f3a71f0a
commit 28a6755c75
13 changed files with 63 additions and 75 deletions

View file

@ -989,52 +989,14 @@ message GraphsIn {
}
message GraphsOut {
// CardsGraphData cards = 1;
// TodayGraphData today = 3;
// ButtonsGraphData buttons = 4;
// repeated HourGraphData hours = 2;
repeated Card cards = 1;
repeated RevlogEntry revlog = 2;
uint32 days_elapsed = 3;
// Based on rollover hour
uint32 next_day_at_secs = 4;
uint32 scheduler_version = 5;
/// Seconds to add to UTC timestamps to get local time.
uint32 local_offset_secs = 7;
uint32 note_count = 10;
}
message CardsGraphData {
uint32 mature_count = 7;
uint32 young_or_learning_count = 8;
uint32 new_count = 9;
uint32 suspended_or_buried_count = 10;
}
message TodayGraphData {
uint32 answer_count = 1;
uint32 answer_millis = 2;
uint32 correct_count = 3;
uint32 learn_count = 4;
uint32 review_count = 5;
uint32 relearn_count = 6;
uint32 early_review_count = 7;
uint32 mature_count = 8;
uint32 mature_correct = 9;
}
message HourGraphData {
uint32 review_count = 1;
uint32 correct_count = 2;
}
message ButtonsGraphData {
repeated uint32 learn = 1;
repeated uint32 young = 2;
repeated uint32 mature = 3;
}
message RevlogEntry {

View file

@ -77,3 +77,10 @@ statistics-today-type-counts = Learn: { $learnCount }, Review: { $reviewCount },
statistics-today-no-cards = No cards have been studied today.
statistics-today-no-mature-cards = No mature cards were studied today.
statistics-today-correct-mature = Correct answers on mature cards: { $correct }/{ $total } ({ $percent }%)
statistics-counts-total-cards = Total
statistics-counts-new-cards = New
statistics-counts-young-cards = Young
statistics-counts-mature-cards = Mature
statistics-counts-suspended-cards = Suspended
statistics-counts-buried-cards = Buried
statistics-counts-title = Card Counts

View file

@ -42,7 +42,6 @@ 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 u32,
note_count: 0,
})
}
}

View file

@ -4,14 +4,18 @@
import pb from "./backend/proto";
import { FluentBundle, FluentResource, FluentNumber } from "@fluent/bundle";
function formatNumbers(args?: Record<string, any>): void {
type RecordVal = number | string | FluentNumber;
function formatNumbers(args?: Record<string, RecordVal>): void {
if (!args) {
return;
}
for (const key of Object.keys(args)) {
if (typeof args[key] === "number") {
args[key] = new FluentNumber(args[key], { maximumSignificantDigits: 2 });
args[key] = new FluentNumber(args[key] as number, {
maximumSignificantDigits: 2,
});
}
}
}
@ -20,7 +24,7 @@ export class I18n {
bundles: FluentBundle[] = [];
TR = pb.BackendProto.FluentString;
tr(id: pb.BackendProto.FluentString, args?: Record<string, any>): string {
tr(id: pb.BackendProto.FluentString, args?: Record<string, RecordVal>): string {
formatNumbers(args);
const key = this.keyName(id);
for (const bundle of this.bundles) {

View file

@ -1,17 +1,38 @@
<script lang="typescript">
import { gatherData, CardCounts } from "./card-counts";
import pb from "../backend/proto";
import { I18n } from "../i18n";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
let cardCounts: CardCounts | null = null;
$: if (sourceData) {
console.log("gathering data");
cardCounts = gatherData(sourceData);
cardCounts = gatherData(sourceData, i18n);
}
</script>
<div class="graph">
<h1>Card Counts</h1>
{JSON.stringify(cardCounts)}
</div>
<style>
.counts-outer {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
</style>
{#if cardCounts}
<div class="graph">
<h1>{cardCounts.title}</h1>
<div class="counts-outer">
{#each cardCounts.counts as count}
<div>
<div>
<b>{count[0]}</b>
</div>
<div>{count[1]}</div>
</div>
{/each}
</div>
</div>
{/if}

View file

@ -125,7 +125,7 @@
<div class="range-box-pad" />
<TodayStats {sourceData} {i18n} />
<CardCounts {sourceData} />
<CardCounts {sourceData} {i18n} />
<FutureDue {sourceData} />
<ReviewsGraph {sourceData} {revlogRange} />
<IntervalsGraph {sourceData} />

View file

@ -15,7 +15,6 @@
let svg = null as HTMLElement | SVGElement | null;
let range: ReviewRange;
let showTime = false;
let tooltip = null as null | HTMLDivElement;
$: switch (revlogRange as RevlogRange) {
case RevlogRange.Month:
@ -38,7 +37,7 @@
}
$: if (graphData) {
renderReviews(svg as SVGElement, bounds, graphData, range, showTime, tooltip);
renderReviews(svg as SVGElement, bounds, graphData, range, showTime);
}
</script>
@ -83,6 +82,4 @@
<AxisLabels {bounds} {xText} {yText} />
</svg>
<div bind:this={tooltip} class="tooltip-area" />
</div>

View file

@ -3,19 +3,15 @@
import pb from "../backend/proto";
import { CardQueue } from "../cards";
import { I18n } from "../i18n";
type Count = [string, number];
export interface CardCounts {
totalCards: number;
totalNotes: number;
newCards: number;
young: number;
mature: number;
suspended: number;
buried: number;
title: string;
counts: Count[];
}
export function gatherData(data: pb.BackendProto.GraphsOut): CardCounts {
const totalNotes = data.noteCount;
export function gatherData(data: pb.BackendProto.GraphsOut, i18n: I18n): CardCounts {
const totalCards = data.cards.length;
let newCards = 0;
let young = 0;
@ -48,13 +44,17 @@ export function gatherData(data: pb.BackendProto.GraphsOut): CardCounts {
}
}
const counts = [
[i18n.tr(i18n.TR.STATISTICS_COUNTS_TOTAL_CARDS), totalCards] as Count,
[i18n.tr(i18n.TR.STATISTICS_COUNTS_NEW_CARDS), newCards] as Count,
[i18n.tr(i18n.TR.STATISTICS_COUNTS_YOUNG_CARDS), young] as Count,
[i18n.tr(i18n.TR.STATISTICS_COUNTS_MATURE_CARDS), mature] as Count,
[i18n.tr(i18n.TR.STATISTICS_COUNTS_SUSPENDED_CARDS), suspended] as Count,
[i18n.tr(i18n.TR.STATISTICS_COUNTS_BURIED_CARDS), buried] as Count,
];
return {
totalCards,
totalNotes,
newCards,
young,
mature,
suspended,
buried,
title: i18n.tr(i18n.TR.STATISTICS_COUNTS_TITLE),
counts,
};
}

View file

@ -7,7 +7,7 @@
*/
import pb from "../backend/proto";
import { extent, histogram, rollup, max, sum, Bin } from "d3-array";
import { extent, histogram, rollup, sum, Bin } from "d3-array";
import { scaleLinear, scaleSequential } from "d3-scale";
import { CardQueue } from "../cards";
import { HistogramData } from "./histogram-graph";
@ -65,7 +65,7 @@ export function buildHistogram(
return null;
}
const [xMinOrig, origXMax] = extent<number>(data.keys());
const [_xMinOrig, origXMax] = extent<number>(data.keys());
const xMin = 0;
let xMax = origXMax;

View file

@ -4,7 +4,7 @@
import { setupI18n } from "../i18n";
import GraphsPage from "./GraphsPage.svelte";
export function graphs(target: HTMLDivElement) {
export function graphs(target: HTMLDivElement): void {
setupI18n().then((i18n) => {
new GraphsPage({
target,

View file

@ -35,7 +35,7 @@ export function histogramGraph(
bounds: GraphBounds,
data: HistogramData
): void {
const binValue = data.binValue ?? ((bin: any) => bin.length as number);
const binValue = data.binValue ?? ((bin: any): number => bin.length as number);
const svg = select(svgElem);
const trans = svg.transition().duration(600) as any;

View file

@ -111,8 +111,7 @@ export function renderReviews(
bounds: GraphBounds,
sourceData: GraphData,
range: ReviewRange,
showTime: boolean,
tooltipArea: HTMLDivElement
showTime: boolean
): void {
const xMax = 0;
let xMin = 0;

View file

@ -2,7 +2,6 @@
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { I18n } from "./i18n";
import { FluentNumber } from "@fluent/bundle";
const SECOND = 1.0;
const MINUTE = 60.0 * SECOND;