extract normal state component out of Start

This commit is contained in:
llama 2025-10-20 10:04:51 +08:00
parent 7b5afb8dd8
commit 1ce305620d
No known key found for this signature in database
GPG key ID: 0B7543854B9413C3
2 changed files with 169 additions and 110 deletions

View file

@ -0,0 +1,160 @@
<!--
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({}, { alertOnError: false }));
let existingPromise = $state(getExistingVersions({}, { alertOnError: false }));
let loadPromise = $derived(Promise.all([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 error: Error | null = $state(null);
const setError = (e: Error) => {
error = e;
};
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 [releases, existing]}
<Action {releases} {existing} {allowBetas} {choose} {uninstall} />
{:catch e}
{setError(e)}
<Warning
warning={$tr.lauuncherFailedToLoadVersions()}
className="alert-danger"
/>
{/await}
{:else}
<Row class="centre m-3">
<AnkiWillStart {res} />
</Row>
{/if}
{:catch e}
{setError(e)}
<Warning warning={$tr.launcherFailedToSync()} className="alert-danger" />
{/await}
{#if error != null}
<Row>
<pre>{error.message}</pre>
</Row>
{/if}
{#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%;
}
.logo {
max-width: 50px;
margin-inline-end: 1em;
-webkit-user-drag: none;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.title {
align-items: center;
}
:global(.centre) {
justify-content: center;
}
pre {
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
</style>

View file

@ -3,79 +3,29 @@ 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 GetLangsResponse_Pair,
type GetMirrorsResponse_Pair,
} from "@generated/anki/launcher_pb";
import {
chooseVersion,
getAvailableVersions,
getExistingVersions,
} from "@generated/backend-launcher";
import { type GetLangsResponse_Pair } from "@generated/anki/launcher_pb";
import Row from "$lib/components/Row.svelte";
import EnumSelectorRow from "$lib/components/EnumSelectorRow.svelte";
import SettingTitle from "$lib/components/SettingTitle.svelte";
import TitledContainer from "$lib/components/TitledContainer.svelte";
import Container from "$lib/components/Container.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 {
langs,
selectedLang = $bindable(),
options,
mirrors,
children,
footer,
}: {
langs: GetLangsResponse_Pair[];
selectedLang: string;
options: OptionsProto;
mirrors: GetMirrorsResponse_Pair[];
children: any;
footer: any;
} = $props();
let releasesPromise = $state(getAvailableVersions({}, { alertOnError: false }));
let existingPromise = $state(getExistingVersions({}, { alertOnError: false }));
let loadPromise = $derived(Promise.all([releasesPromise, existingPromise]));
const availableLangs = $derived(
langs.map((p) => ({ label: p.name, value: p.locale })),
);
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 error: Error | null = $state(null);
const setError = (e: Error) => {
error = e;
};
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>
<Container
@ -101,55 +51,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{$tr.launcherLanguage()}
</SettingTitle>
</EnumSelectorRow>
{#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 [releases, existing]}
<Action {releases} {existing} {allowBetas} {choose} />
{:catch e}
{setError(e)}
<Warning
warning={$tr.lauuncherFailedToLoadVersions()}
className="alert-danger"
/>
{/await}
{:else}
<Row class="centre m-3">
<AnkiWillStart {res} />
</Row>
{/if}
{:catch e}
{setError(e)}
<Warning
warning={$tr.launcherFailedToSync()}
className="alert-danger"
/>
{/await}
{#if error != null}
<Row>
<pre>{error.message}</pre>
</Row>
{/if}
{@render children?.()}
</TitledContainer>
</Row>
<Term bind:term bind:open={termOpen} />
{#if !chosen}
<Row class="row-columns">
<Options
{mirrors}
bind:allowBetas
bind:downloadCaching
bind:selectedMirror
/>
</Row>
{/if}
{@render footer?.()}
</Container>
<style lang="scss">
@ -182,12 +89,4 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
:global(.centre) {
justify-content: center;
}
pre {
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
</style>