Files
STARTLINER/src/components/StartButton.vue

156 lines
4.3 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 { invoke } from '../invoke';
import { usePrfStore } from '../stores';
const prf = usePrfStore();
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 `Package missing: ${o.MissingRemotePackage}`;
} else if ('MissingLocalPackage' in o) {
return `Package missing: ${o.MissingLocalPackage}`;
} else if ('MissingDependency' in o) {
return `Dependency missing: ${(o.MissingDependency as string[]).join(' ')}`;
} else if ('MissingTool' in o) {
return `Tool missing: ${o.MissingTool}`;
} else {
return 'Unknown error';
}
});
confirmDialog.require({
message: message.join('\n'),
header: 'Start check failed',
acceptLabel: 'Run anyway',
rejectLabel: '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 'The game path must be specified';
}
if (prf.current?.data.sgt.amfs.length === 0) {
return 'The amfs path must be specified';
}
if (
prf.current?.data.sgt.hook === null ||
prf.current?.data.sgt.hook === undefined
) {
return 'A segatools hook package is necessary';
}
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 = [
{
label: 'Refresh and start',
icon: 'pi pi-sync',
command: async () => await startline(false, true),
},
{
label: 'Start unchecked',
icon: 'pi pi-exclamation-circle',
command: async () => await startline(true, false),
},
{
label: 'Create desktop shortcut',
icon: 'pi pi-link',
command: createShortcut,
},
];
const menu = ref();
const showContextMenu = (event: Event) => {
event.preventDefault();
menu.value.show(event);
};
</script>
<template>
<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="startline(false, false)"
@contextmenu="showContextMenu"
/>
<Button
v-else-if="startStatus === 'preparing'"
disabled
icon="pi pi-spin pi-spinner"
label="START"
aria-label="start"
size="small"
class="m-2.5"
/>
<Button
v-else
:disabled="false"
icon="pi pi-ban"
label="STOP"
aria-label="stop"
size="small"
class="m-2.5"
@click="kill()"
/>
</template>