From 8a3a7ad12a89cd78a0cbfafd28fd8265de81c76a Mon Sep 17 00:00:00 2001 From: Francisco Salgueiro Date: Fri, 20 Oct 2023 14:13:07 +0100 Subject: [PATCH] add persistance to more values --- src/atoms/atoms.ts | 33 +++++++++++--- .../panels/analysis/AnalysisPanel.tsx | 17 +++++++- .../panels/database/DatabasePanel.tsx | 31 ++++++++----- src/components/panels/info/PgnInput.tsx | 43 +++++++------------ 4 files changed, 79 insertions(+), 45 deletions(-) diff --git a/src/atoms/atoms.ts b/src/atoms/atoms.ts index 17d244a7..76d81e2e 100644 --- a/src/atoms/atoms.ts +++ b/src/atoms/atoms.ts @@ -3,7 +3,7 @@ import { Tab, genID } from "@/utils/tabs"; import { MantineColor } from "@mantine/core"; import { Session } from "../utils/session"; import { PrimitiveAtom, atom } from "jotai"; -import { DatabaseInfo } from "@/utils/db"; +import { DatabaseInfo, PositionQuery } from "@/utils/db"; import { MissingMove } from "@/utils/repertoire"; import { Card, buildFromTree } from "@/components/files/opening"; import { GameHeaders, TreeNode } from "@/utils/treeReducer"; @@ -12,7 +12,7 @@ import EngineSettings from "@/components/panels/analysis/EngineSettings"; import { AsyncStringStorage } from "jotai/vanilla/utils/atomWithStorage"; import { BaseDirectory, readTextFile, removeFile, writeTextFile } from "@tauri-apps/api/fs"; import { Engine } from "@/utils/engines"; -import { LichessGamesOptions } from "@/utils/lichess/lichessexplorer"; +import { LichessGamesOptions, MasterGamesOptions } from "@/utils/lichess/lichessexplorer"; const options = { dir: BaseDirectory.AppData }; @@ -142,16 +142,16 @@ function tabValue( return atom( (get) => { const tab = get(currentTabAtom); - if (!tab) return null; + if (!tab) throw new Error("No tab selected"); const atom = family(tab.value); return get(atom); }, (get, set, newValue: T | ((currentValue: T) => T)) => { const tab = get(currentTabAtom); - if (!tab) return null; + if (!tab) throw new Error("No tab selected"); const nextValue = typeof newValue === "function" - ? newValue(get(tabValue(family))!) + ? newValue(get(tabValue(family))) : newValue; const atom = family(tab.value); set(atom, nextValue); @@ -173,6 +173,29 @@ const lichessOptionsFamily = atomFamily((tab: string) => atom atom({})); +export const currentMasterOptionsAtom = tabValue(masterOptionsFamily); + +const dbTypeFamily = atomFamily((tab: string) => atom<"local" | "lch_all" | "lch_master">("local")); +export const currentDbTypeAtom = tabValue(dbTypeFamily); + +const dbTabFamily = atomFamily((tab: string) => atom("stats")); +export const currentDbTabAtom = tabValue(dbTabFamily); + +const analysisTabFamily = atomFamily((tab: string) => atom("engines")); +export const currentAnalysisTabAtom = tabValue(analysisTabFamily); + +const positionQueryFamily = atomFamily((tab: string) => atom({ value: "", type: "exact" })); +export const currentPositionQueryAtom = tabValue(positionQueryFamily); + +const pgnOptionsFamily = atomFamily((tab: string) => atom({ + comments: true, + annotations: true, + variations: true, + symbols: false, +})); +export const currentPgnOptionsAtom = tabValue(pgnOptionsFamily); + // Practice const practicingFamily = atomFamily((tab: string) => atom(false)); diff --git a/src/components/panels/analysis/AnalysisPanel.tsx b/src/components/panels/analysis/AnalysisPanel.tsx index d9672aa1..9832023c 100644 --- a/src/components/panels/analysis/AnalysisPanel.tsx +++ b/src/components/panels/analysis/AnalysisPanel.tsx @@ -23,7 +23,12 @@ import { TreeStateContext } from "@/components/common/TreeStateContext"; import BestMoves from "./BestMoves"; import EngineSelection from "./EngineSelection"; import React from "react"; -import { allEnabledAtom, enableAllAtom, enginesAtom } from "@/atoms/atoms"; +import { + allEnabledAtom, + currentAnalysisTabAtom, + enableAllAtom, + enginesAtom, +} from "@/atoms/atoms"; import { useAtom, useAtomValue } from "jotai"; import LogsPanel from "./LogsPanel"; @@ -60,8 +65,16 @@ function AnalysisPanel({ const allEnabled = allEnabledLoader.state === "hasData" && allEnabledLoader.data; + const [tab, setTab] = useAtom(currentAnalysisTabAtom); + return ( - + setTab(v!)} + > Engines Report diff --git a/src/components/panels/database/DatabasePanel.tsx b/src/components/panels/database/DatabasePanel.tsx index 9ff9b78f..0c13b501 100644 --- a/src/components/panels/database/DatabasePanel.tsx +++ b/src/components/panels/database/DatabasePanel.tsx @@ -1,7 +1,15 @@ import { Alert, Group, SegmentedControl, Tabs, Text } from "@mantine/core"; -import { memo, useEffect, useState } from "react"; +import { memo, useEffect } from "react"; import { Opening, PositionQuery, searchPosition } from "@/utils/db"; -import { currentLichessOptionsAtom, currentTabAtom, referenceDbAtom } from "@/atoms/atoms"; +import { + currentDbTabAtom, + currentDbTypeAtom, + currentLichessOptionsAtom, + currentMasterOptionsAtom, + currentPositionQueryAtom, + currentTabAtom, + referenceDbAtom, +} from "@/atoms/atoms"; import { useAtom, useAtomValue } from "jotai"; import { convertToNormalized, @@ -33,6 +41,7 @@ function sortOpenings(openings: Opening[]) { } async function fetchOpening(query: PositionQuery, db: DBType, tab: string, lichessOptions: LichessGamesOptions, masterOptions: MasterGamesOptions) { + if (query.value === "") return { openings: [], games: [] }; return match(db) .with({ type: "lch_all" }, async () => { const data = await getLichessGames(query.value, lichessOptions); @@ -71,15 +80,15 @@ async function fetchOpening(query: PositionQuery, db: DBType, tab: string, liche function DatabasePanel({ height, fen }: { height: number; fen: string }) { const referenceDatabase = useAtomValue(referenceDbAtom); - const [db, setDb] = useState<"local" | "lch_all" | "lch_master">("local"); + const [debouncedFen] = useDebouncedValue(fen, 50); const [lichessOptions, setLichessOptions] = useAtom(currentLichessOptionsAtom); + const [masterOptions, setMasterOptions] = useAtom(currentMasterOptionsAtom); const [debouncedLichessOptions] = useDebouncedValue(lichessOptions, 500); - const [masterOptions, setMasterOptions] = useState({}); - const [query, setQuery] = useState({ value: fen, type: "exact" }); - const [debouncedFen] = useDebouncedValue(fen, 50); + const [query, setQuery] = useAtom(currentPositionQueryAtom); + const [db, setDb] = useAtom(currentDbTypeAtom); useEffect(() => { - setQuery((q) => ({ ...q, value: debouncedFen })); + setQuery((q) => (q.type === "exact" && q.value != debouncedFen) ? ({ type: "exact", value: debouncedFen }): q); }, [debouncedFen, setQuery]); const dbType: DBType = match(db) @@ -100,10 +109,10 @@ function DatabasePanel({ height, fen }: { height: number; fen: string }) { isLoading, error, } = useSWR([dbType, query, debouncedLichessOptions, masterOptions], async ([dbType, query, lichessOptions, masterOptions]) => { - return fetchOpening(query, dbType, tab?.value || "", lichessOptions!, masterOptions); + return fetchOpening(query, dbType, tab?.value || "", lichessOptions, masterOptions); }); - const [tabType, setTabType] = useState("stats"); + const [tabType, setTabType] = useAtom(currentDbTabAtom); const grandTotal = openingData?.openings?.reduce( (acc, curr) => acc + curr.black + curr.white + curr.draw, 0 @@ -138,7 +147,7 @@ function DatabasePanel({ height, fen }: { height: number; fen: string }) { orientation="vertical" placement="right" value={tabType} - onTabChange={setTabType} + onTabChange={(v) => setTabType(v!)} > @@ -174,7 +183,7 @@ function DatabasePanel({ height, fen }: { height: number; fen: string }) { /> ).with("lch_all", () => ).with("lch_master", () => diff --git a/src/components/panels/info/PgnInput.tsx b/src/components/panels/info/PgnInput.tsx index a8aded2c..b882182a 100644 --- a/src/components/panels/info/PgnInput.tsx +++ b/src/components/panels/info/PgnInput.tsx @@ -1,21 +1,19 @@ import { Checkbox, Group, Stack, Text, Textarea } from "@mantine/core"; -import { useToggle } from "@mantine/hooks"; import { memo, useMemo } from "react"; import { getPGN } from "@/utils/chess"; import { GameHeaders, TreeNode } from "@/utils/treeReducer"; +import { useAtom } from "jotai"; +import { currentPgnOptionsAtom } from "@/atoms/atoms"; function PgnInput({ root, headers }: { root: TreeNode; headers: GameHeaders }) { - const [comments, toggleComments] = useToggle([true, false]); - const [annotations, toggleAnnotations] = useToggle([true, false]); - const [variations, toggleVariations] = useToggle([true, false]); - const [symbols, toggleSymbols] = useToggle(); + const [options, setOptions] = useAtom(currentPgnOptionsAtom) const pgn = getPGN(root, { headers: headers, - symbols: annotations, - comments, - variations, - specialSymbols: symbols, + symbols: options.annotations, + comments: options.comments, + variations: options.variations, + specialSymbols: options.symbols, }); const controls = useMemo( @@ -26,40 +24,31 @@ function PgnInput({ root, headers }: { root: TreeNode; headers: GameHeaders }) { toggleComments()} + checked={options.comments} + onChange={() => setOptions({ ...options, comments: !options.comments })} /> toggleAnnotations()} + checked={options.annotations} + onChange={() => setOptions({ ...options, annotations: !options.annotations })} /> toggleVariations()} + checked={options.variations} + onChange={() => setOptions({ ...options, variations: !options.variations })} /> toggleSymbols()} + checked={options.symbols} + onChange={() => setOptions({ ...options, symbols: !options.symbols })} /> ), - [ - comments, - annotations, - variations, - symbols, - toggleComments, - toggleAnnotations, - toggleVariations, - toggleSymbols, - ] + [options, setOptions] ); const pgnArea = useMemo(