Files
STARTLINER/src/components/StartButton.vue
2025-04-22 21:34:55 +00:00

217 lines
6.0 KiB
Vue

<script setup lang="ts">
import { Ref, computed, ref } from 'vue';
import Button from 'primevue/button';
import ContextMenu from 'primevue/contextmenu';
import { useConfirm } from 'primevue/useconfirm';
import { listen } from '@tauri-apps/api/event';
import { getCurrentWindow } from '@tauri-apps/api/window';
import Onboarding from './Onboarding.vue';
import { invoke } from '../invoke';
import { useClientStore, usePrfStore } from '../stores';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const prf = usePrfStore();
const client = useClientStore();
const confirmDialog = useConfirm();
type StartStatus = 'ready' | 'preparing' | 'running';
const startStatus: Ref<StartStatus> = ref('ready');
const startline = async (force: boolean, refresh: boolean) => {
startStatus.value = 'preparing';
if (!force) {
const start_check: object[] = await invoke('start_check');
if (start_check.length > 0) {
const message = start_check.map((o) => {
if ('MissingRemotePackage' in o) {
return `${t('start.error.package')}: ${o.MissingRemotePackage}`;
} else if ('MissingLocalPackage' in o) {
return `${t('start.error.package')}: ${o.MissingLocalPackage}`;
} else if ('MissingDependency' in o) {
return `${t('start.error.dependency')}: ${(o.MissingDependency as string[]).join(' ')}`;
} else if ('MissingTool' in o) {
return `${t('start.error.tool')}: ${o.MissingTool}`;
} else {
return t('start.error.unknown');
}
});
confirmDialog.require({
message: message.join('\n'),
header: t('start.failed'),
acceptLabel: t('start.accept'),
rejectLabel: t('cancel'),
accept: () => {
startline(true, refresh);
},
});
startStatus.value = 'ready';
return;
}
}
try {
await invoke('save_current_profile');
await invoke('startline', { refresh });
} catch (_) {
startStatus.value = 'ready';
}
};
const kill = async () => {
await invoke('kill');
};
const disabledTooltip = computed(() => {
if (prf.current?.data.sgt.target.length === 0) {
return t('start.tooltip.game');
}
if (prf.current?.data.sgt.amfs.length === 0) {
return t('start.tooltip.amfs');
}
if (
prf.current?.data.sgt.hook === null ||
prf.current?.data.sgt.hook === undefined
) {
return t('start.tooltip.segatools');
}
return null;
});
listen('launch-start', () => {
startStatus.value = 'running';
getCurrentWindow().minimize();
});
listen('launch-end', () => {
startStatus.value = 'ready';
getCurrentWindow().unminimize();
getCurrentWindow().setFocus();
});
const createShortcut = async () => {
const current = prf.current;
if (current !== null) {
await invoke('create_shortcut', {
profileMeta: current.meta,
});
}
};
const menuItems = computed(() => {
const base = [
{
label: t('start.button.unchecked'),
icon: 'pi pi-exclamation-circle',
command: async () => await startline(true, false),
},
{
label: t('start.button.shortcut'),
icon: 'pi pi-link',
command: createShortcut,
},
{
label: t('start.button.help'),
icon: 'pi pi-question-circle',
command: () => {
onboardingFirstTime.value = false;
onboardingVisible.value = true;
},
},
];
if (prf.current === null) {
return [];
}
if (prf.current.meta.game === 'chunithm') {
return base;
}
if (prf.current.meta.game === 'ongeki') {
return [
{
label: t('start.button.refresh'),
icon: 'pi pi-sync',
command: async () => await startline(false, true),
},
...base,
{
label: t('start.button.cache'),
icon: 'pi pi-trash',
command: async () => {},
},
];
}
});
const menu = ref();
const showContextMenu = (event: Event) => {
event.preventDefault();
menu.value.show(event);
};
const onboardingVisible = ref(false);
const onboardingFirstTime = ref(false);
const tryStart = () => {
const game = prf.current?.meta.game;
if (game !== undefined) {
if (client.onboarded.includes(game)) {
startline(false, false);
} else {
onboardingVisible.value = true;
onboardingFirstTime.value = true;
client.setOnboarded(game);
}
}
};
</script>
<template>
<Onboarding
:visible="onboardingVisible"
:first-time="onboardingFirstTime"
:on-finish="
() => {
onboardingVisible = false;
if (onboardingFirstTime === true) {
startline(false, false);
}
}
"
/>
<ContextMenu ref="menu" :model="menuItems" />
<Button
v-if="startStatus === 'ready'"
v-tooltip="disabledTooltip"
:disabled="disabledTooltip !== null"
icon="pi pi-play"
label="START"
aria-label="start"
size="small"
class="m-2.5"
@click="tryStart"
@contextmenu="showContextMenu"
/>
<Button
v-else-if="startStatus === 'preparing'"
disabled
icon="pi pi-spin pi-spinner"
:label="t('start.button.start')"
aria-label="start"
size="small"
class="m-2.5"
/>
<Button
v-else
:disabled="false"
icon="pi pi-ban"
:label="t('start.button.stop')"
aria-label="stop"
size="small"
class="m-2.5"
@click="kill()"
/>
</template>