Generalize ts/graphs/preferences to ts/sveltelib/preferences

This commit is contained in:
Henrik Giesel 2021-04-14 23:46:13 +02:00
parent b696635afc
commit 13decbe608
10 changed files with 124 additions and 103 deletions

View file

@ -4,6 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import type pb from "anki/backend_proto";
import type { PreferenceStore } from "sveltelib/preferences";
import { createEventDispatcher } from "svelte";
import Graph from "./Graph.svelte";
@ -17,11 +18,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { HistogramData } from "./histogram-graph";
import { gatherData, buildHistogram } from "./added";
import type { GraphData } from "./added";
import type { PreferenceStore } from "./preferences";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
import * as tr from "anki/i18n";
export let preferences: PreferenceStore;
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
let histogramData = null as HistogramData | null;
let tableData: TableDatum[] = [];

View file

@ -4,6 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import type pb from "anki/backend_proto";
import type { PreferenceStore } from "sveltelib/preferences";
import { createEventDispatcher } from "svelte";
@ -15,11 +16,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { defaultGraphBounds, RevlogRange } from "./graph-helpers";
import type { SearchEventMap } from "./graph-helpers";
import { gatherData, renderCalendar } from "./calendar";
import type { PreferenceStore } from "./preferences";
import type { GraphData } from "./calendar";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let preferences: PreferenceStore | null = null;
export let sourceData: pb.BackendProto.GraphsOut;
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
export let revlogRange: RevlogRange;
import * as tr from "anki/i18n";
export let nightMode: boolean;

View file

@ -5,6 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="typescript">
import { createEventDispatcher } from "svelte";
import type pb from "anki/backend_proto";
import type { PreferenceStore } from "sveltelib/preferences";
import Graph from "./Graph.svelte";
import InputBox from "./InputBox.svelte";
@ -13,7 +14,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { SearchEventMap } from "./graph-helpers";
import { gatherData, renderCards } from "./card-counts";
import type { GraphData, TableDatum } from "./card-counts";
import type { PreferenceStore } from "./preferences";
export let sourceData: pb.BackendProto.GraphsOut;
import * as tr2 from "anki/i18n";

View file

@ -4,6 +4,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import type pb from "anki/backend_proto";
import * as tr from "anki/i18n";
import type { PreferenceStore } from "sveltelib/preferences";
import { createEventDispatcher } from "svelte";
@ -14,11 +16,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { HistogramData } from "./histogram-graph";
import { gatherData, prepareData } from "./ease";
import type { TableDatum, SearchEventMap } from "./graph-helpers";
import type { PreferenceStore } from "./preferences";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
import * as tr from "anki/i18n";
export let preferences: PreferenceStore;
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
const dispatch = createEventDispatcher<SearchEventMap>();

View file

@ -12,17 +12,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import HistogramGraph from "./HistogramGraph.svelte";
import GraphRangeRadios from "./GraphRangeRadios.svelte";
import TableData from "./TableData.svelte";
import type { PreferenceStore } from "sveltelib/preferences";
import type { HistogramData } from "./histogram-graph";
import { GraphRange, RevlogRange } from "./graph-helpers";
import type { TableDatum, SearchEventMap } from "./graph-helpers";
import { gatherData, buildHistogram } from "./future-due";
import type { GraphData } from "./future-due";
import type { PreferenceStore } from "./preferences";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
import * as tr from "anki/i18n";
export let preferences: PreferenceStore;
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
const dispatch = createEventDispatcher<SearchEventMap>();

View file

@ -6,6 +6,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { timeSpan, MONTH } from "anki/time";
import type pb from "anki/backend_proto";
import type { PreferenceStore } from "sveltelib/preferences";
import { createEventDispatcher } from "svelte";
import Graph from "./Graph.svelte";
@ -21,11 +22,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} from "./intervals";
import type { IntervalGraphData } from "./intervals";
import type { TableDatum, SearchEventMap } from "./graph-helpers";
import type { PreferenceStore } from "./preferences";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
import * as tr from "anki/i18n";
export let preferences: PreferenceStore;
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
const dispatch = createEventDispatcher<SearchEventMap>();

View file

@ -5,11 +5,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="typescript">
import type { Writable } from "svelte/store";
import pb from "anki/backend_proto";
import useAsync from "sveltelib/async";
import useAsyncReactive from "sveltelib/asyncReactive";
import { getPreferences } from "sveltelib/preferences";
import { getGraphData, daysToRevlogRange } from "./graph-helpers";
import { getPreferences } from "./preferences";
import {
getGraphData,
getGraphPreferences,
setGraphPreferences,
daysToRevlogRange,
} from "./graph-helpers";
export let search: Writable<string>;
export let days: Writable<number>;
@ -24,7 +31,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
loading: prefsLoading,
error: prefsError,
value: prefsValue,
} = useAsync(() => getPreferences());
} = useAsync(() =>
getPreferences(
getGraphPreferences,
setGraphPreferences,
pb.BackendProto.GraphPreferences.toObject.bind(
pb.BackendProto.GraphPreferences
)
)
);
$: revlogRange = daysToRevlogRange($days);

View file

@ -8,7 +8,7 @@
import pb from "anki/backend_proto";
import type { Selection } from "d3";
import type { PreferencePayload } from "./preferences";
import type { PreferencePayload } from "sveltelib/preferences";
import { postRequest } from "anki/postrequest";
export async function getGraphData(
@ -26,13 +26,13 @@ export async function getGraphPreferences(): Promise<pb.BackendProto.GraphPrefer
);
}
export async function setGraphPreferences(prefs: PreferencePayload): Promise<void> {
return (async (): Promise<void> => {
await postRequest(
"/_anki/setGraphPreferences",
pb.BackendProto.GraphPreferences.encode(prefs).finish()
);
})();
export async function setGraphPreferences(
prefs: PreferencePayload<pb.BackendProto.GraphPreferences>
): Promise<void> {
await postRequest(
"/_anki/setGraphPreferences",
pb.BackendProto.GraphPreferences.encode(prefs).finish()
);
}
// amount of data to fetch from backend

View file

@ -1,79 +0,0 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
// languageServerHost taken from MIT sources - see below.
import pb from "anki/backend_proto";
import { getGraphPreferences, setGraphPreferences } from "./graph-helpers";
import { Writable, writable, get } from "svelte/store";
export interface CustomStore<T> extends Writable<T> {
subscribe: (getter: (value: T) => void) => () => void;
set: (value: T) => void;
}
export type PreferenceStore = {
[K in keyof Omit<pb.BackendProto.GraphPreferences, "toJSON">]: CustomStore<
pb.BackendProto.GraphPreferences[K]
>;
};
export type PreferencePayload = {
[K in keyof Omit<
pb.BackendProto.GraphPreferences,
"toJSON"
>]: pb.BackendProto.GraphPreferences[K];
};
function createPreference<T>(
initialValue: T,
savePreferences: () => void
): CustomStore<T> {
const { subscribe, set, update } = writable(initialValue);
return {
subscribe,
set: (value: T): void => {
set(value);
savePreferences();
},
update: (updater: (value: T) => T): void => {
update(updater);
savePreferences();
},
};
}
function preparePreferences(
GraphPreferences: pb.BackendProto.GraphPreferences
): PreferenceStore {
const preferences: Partial<PreferenceStore> = {};
function constructPreferences(): PreferencePayload {
const payload: Partial<PreferencePayload> = {};
for (const key in preferences as PreferenceStore) {
payload[key] = get(preferences[key]);
}
return payload as PreferencePayload;
}
function savePreferences(): void {
setGraphPreferences(constructPreferences());
}
for (const [key, value] of Object.entries(
pb.BackendProto.GraphPreferences.toObject(GraphPreferences, {
defaults: true,
})
)) {
preferences[key] = createPreference(value, savePreferences);
}
return preferences as PreferenceStore;
}
export async function getPreferences(): Promise<PreferenceStore> {
const initialPreferences = await getGraphPreferences();
return preparePreferences(initialPreferences);
}

View file

@ -0,0 +1,85 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
// languageServerHost taken from MIT sources - see below.
import { Writable, writable, get } from "svelte/store";
// import pb from "anki/backend_proto";
// export async function getGraphPreferences(): Promise<pb.BackendProto.GraphPreferences> {
// export async function setGraphPreferences(prefs: PreferencePayload): Promise<void> {
// pb.BackendProto.GraphPreferences.toObject(Preferences, {
export interface CustomStore<T> extends Writable<T> {
subscribe: (getter: (value: T) => void) => () => void;
set: (value: T) => void;
}
export type PreferenceStore<T> = {
[K in keyof Omit<T, "toJSON">]: CustomStore<T[K]>;
};
export type PreferencePayload<T> = {
[K in keyof Omit<T, "toJSON">]: T[K];
};
export type PreferenceRaw<T> = {
[K in keyof T]: T[K];
};
function createPreference<T>(
initialValue: T,
savePreferences: () => void
): CustomStore<T> {
const { subscribe, set, update } = writable(initialValue);
return {
subscribe,
set: (value: T): void => {
set(value);
savePreferences();
},
update: (updater: (value: T) => T): void => {
update(updater);
savePreferences();
},
};
}
function preparePreferences<T>(
Preferences: T,
setter: (payload: PreferencePayload<T>) => Promise<void>,
toObject: (preferences: T, options: { defaults: boolean }) => PreferenceRaw<T>
): PreferenceStore<T> {
const preferences: Partial<PreferenceStore<T>> = {};
function constructPreferences(): PreferencePayload<T> {
const payload: Partial<PreferencePayload<T>> = {};
for (const key in preferences as PreferenceStore<T>) {
payload[key] = get(preferences[key]);
}
return payload as PreferencePayload<T>;
}
function savePreferences(): void {
setter(constructPreferences());
}
for (const [key, value] of Object.entries(
toObject(Preferences, { defaults: true })
)) {
preferences[key] = createPreference(value, savePreferences);
}
return preferences as PreferenceStore<T>;
}
export async function getPreferences<T>(
getter: () => Promise<T>,
setter: (payload: PreferencePayload<T>) => Promise<void>,
toObject: (preferences: T, options: { defaults: boolean }) => PreferenceRaw<T>
): Promise<PreferenceStore<T>> {
const initialPreferences = await getter();
return preparePreferences(initialPreferences, setter, toObject);
}