Anki/qt/launcher-gui/src/routes/Normal.svelte

148 lines
4.1 KiB
Svelte

<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import {
Mirror,
type Options as OptionsProto,
type ChooseVersionResponse,
type GetMirrorsResponse_Pair,
} from "@generated/anki/launcher_pb";
import {
chooseVersion,
getAvailableVersions,
getExistingVersions,
} from "@generated/backend-launcher";
import Row from "$lib/components/Row.svelte";
import { tr } from "./stores";
import Warning from "./Warning.svelte";
import Action from "./Action.svelte";
import Spinner from "./Spinner.svelte";
import Options from "./Options.svelte";
import Term from "./Term.svelte";
import AnkiWillStart from "./AnkiWillStart.svelte";
import type { Terminal } from "@xterm/xterm";
let {
options,
mirrors,
uninstall,
footer = $bindable(),
}: {
options: OptionsProto;
mirrors: GetMirrorsResponse_Pair[];
uninstall: (() => void) | null;
footer: any; // https://github.com/sveltejs/svelte/issues/15182
} = $props();
footer = _footer;
let releasesPromise = $state(getAvailableVersions({}));
let existingPromise = $state(getExistingVersions({}));
let loadPromise = $derived(Promise.any([releasesPromise, existingPromise]));
let allowBetas = $state(options.allowBetas);
let downloadCaching = $state(options.downloadCaching);
let selectedMirror = $state(Mirror.DISABLED);
let choosePromise: Promise<ChooseVersionResponse | null> = $state(
Promise.resolve(null),
);
let term: Terminal | undefined = $state(undefined);
let termOpen = $state(false);
let chosen = $state(false);
const choose = (version: string, keepExisting: boolean, current?: string) => {
chosen = true;
term?.reset();
choosePromise = chooseVersion({
version,
keepExisting,
options: { allowBetas, downloadCaching, mirror: selectedMirror },
...(current ? { current } : {}),
});
};
</script>
{#await choosePromise}
<Row class="centre m-3">
<Spinner label={$tr.launcherSyncing()} />
</Row>
{:then res}
{#if res === null}
{#await loadPromise}
<Row class="centre m-3">
<Spinner label={$tr.launcherLoadingVersions()} />
</Row>
{:then}
<Action
{releasesPromise}
{existingPromise}
{allowBetas}
{choose}
{uninstall}
/>
{#await releasesPromise catch e}
<Row>
<pre>{e.message}</pre>
</Row>
{/await}
{:catch e: AggregateError}
<Warning
warning={$tr.launcherFailedToGetExistingAndAvailable()}
className="alert-danger"
/>
{#each e.errors as err}
<Row>
<pre>{err.message}</pre>
</Row>
{/each}
{/await}
{:else}
<Row class="centre m-3">
<AnkiWillStart {res} />
</Row>
{/if}
{:catch e}
<Warning warning={$tr.launcherFailedToSync()} className="alert-danger" />
<Row>
<pre>{e.message}</pre>
</Row>
{/await}
{#snippet _footer()}
<Term bind:term bind:open={termOpen} />
{#if !chosen}
<Row class="row-columns">
<Options
{mirrors}
bind:allowBetas
bind:downloadCaching
bind:selectedMirror
/>
</Row>
{/if}
{/snippet}
<style lang="scss">
:root {
font-size: 16px;
font-weight: 400;
text-rendering: optimizeLegibility;
font-synthesis: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
:global(.centre) {
justify-content: center;
}
pre {
white-space: pre-wrap;
}
</style>