forked from akanyan/STARTLINER
157 lines
4.7 KiB
Vue
157 lines
4.7 KiB
Vue
<script setup lang="ts">
|
|
import { Ref, computed, ref } from 'vue';
|
|
import Button from 'primevue/button';
|
|
import ConfirmDialog from 'primevue/confirmdialog';
|
|
import ScrollPanel from 'primevue/scrollpanel';
|
|
import { useConfirm } from 'primevue/useconfirm';
|
|
import { listen } from '@tauri-apps/api/event';
|
|
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) => {
|
|
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}`;
|
|
} else if ('MissingTool' in o) {
|
|
return `Tool missing: ${o.MissingTool}`;
|
|
} else {
|
|
return 'Unknown error';
|
|
}
|
|
});
|
|
confirmDialog.require({
|
|
message: message.join('\n'),
|
|
header: 'Start check failed',
|
|
accept: () => {
|
|
startline(true);
|
|
},
|
|
});
|
|
startStatus.value = 'ready';
|
|
return;
|
|
}
|
|
}
|
|
try {
|
|
await invoke('save_current_profile');
|
|
await invoke('startline');
|
|
} catch (_) {
|
|
startStatus.value = 'ready';
|
|
}
|
|
};
|
|
|
|
const kill = async () => {
|
|
await invoke('kill');
|
|
startStatus.value = 'ready';
|
|
};
|
|
|
|
const disabledTooltip = computed(() => {
|
|
if (prf.current?.sgt.target.length === 0) {
|
|
return 'The game path must be specified';
|
|
}
|
|
if (prf.current?.sgt.amfs.length === 0) {
|
|
return 'The amfs path must be specified';
|
|
}
|
|
if (prf.current?.sgt.hook === null || prf.current?.sgt.hook === undefined) {
|
|
return 'A segatools hook package is necessary';
|
|
}
|
|
return null;
|
|
});
|
|
|
|
listen('launch-start', () => {
|
|
startStatus.value = 'running';
|
|
});
|
|
|
|
listen('launch-end', () => {
|
|
startStatus.value = 'ready';
|
|
});
|
|
|
|
const messageSplit = (message: any) => {
|
|
return message.message?.split('\n');
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<ConfirmDialog>
|
|
<template #container="{ message, acceptCallback, rejectCallback }">
|
|
<div
|
|
class="flex flex-col p-8 bg-surface-0 dark:bg-surface-900 rounded"
|
|
>
|
|
<span class="font-bold self-center text-2xl block mb-2 mt-2">{{
|
|
message.header
|
|
}}</span>
|
|
<ScrollPanel
|
|
v-if="messageSplit(message).length > 5"
|
|
style="width: 100%; height: 40vh"
|
|
>
|
|
<p v-for="m in messageSplit(message)">
|
|
{{ m }}
|
|
</p></ScrollPanel
|
|
>
|
|
<div v-else>
|
|
<p v-for="m in messageSplit(message)">
|
|
{{ m }}
|
|
</p>
|
|
</div>
|
|
<div class="flex self-center items-center gap-2 mt-6">
|
|
<Button
|
|
label="Run anyway"
|
|
@click="acceptCallback"
|
|
size="small"
|
|
class="w-32"
|
|
></Button>
|
|
<Button
|
|
label="Cancel"
|
|
outlined
|
|
size="small"
|
|
@click="rejectCallback"
|
|
class="w-32"
|
|
></Button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</ConfirmDialog>
|
|
<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)"
|
|
/>
|
|
<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>
|