forked from akanyan/STARTLINER
feat: new error banner, qol
This commit is contained in:
@ -63,7 +63,7 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
||||
if let Some(p) = &mut appd.profile {
|
||||
log::debug!("{}", hash);
|
||||
p.line_up(hash, refresh, app.clone()).await
|
||||
.map_err(|e| format!("Lineup failed:\n{}", e))?;
|
||||
.map_err(|e| e.to_string())?;
|
||||
let app_clone = app.clone();
|
||||
let p_clone = p.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
|
@ -88,7 +88,9 @@ impl Display {
|
||||
settings.borrow_mut().resolution = Resolution::new(width, height);
|
||||
}
|
||||
|
||||
display_set.apply()?;
|
||||
display_set.apply().map_err(
|
||||
|_| anyhow!("The selected monitor has been disconnected or doesn't support the chosen display mode")
|
||||
)?;
|
||||
displayz::refresh()?;
|
||||
|
||||
log::debug!("prepare display: done");
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { Ref, computed, onMounted, ref } from 'vue';
|
||||
import Button from 'primevue/button';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import InputIcon from 'primevue/inputicon';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import Tab from 'primevue/tab';
|
||||
@ -8,13 +9,19 @@ import TabList from 'primevue/tablist';
|
||||
import TabPanel from 'primevue/tabpanel';
|
||||
import TabPanels from 'primevue/tabpanels';
|
||||
import Tabs from 'primevue/tabs';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import ModList from './ModList.vue';
|
||||
import ModStore from './ModStore.vue';
|
||||
import OptionList from './OptionList.vue';
|
||||
import ProfileList from './ProfileList.vue';
|
||||
import StartButton from './StartButton.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import { useClientStore, useGeneralStore, usePkgStore, usePrfStore } from '../stores';
|
||||
import {
|
||||
useClientStore,
|
||||
useGeneralStore,
|
||||
usePkgStore,
|
||||
usePrfStore,
|
||||
} from '../stores';
|
||||
import { Dirs } from '../types';
|
||||
|
||||
const pkg = usePkgStore();
|
||||
@ -56,35 +63,81 @@ onMounted(async () => {
|
||||
});
|
||||
});
|
||||
|
||||
const errorVisible = ref(false);
|
||||
const errorMessage = ref('No error');
|
||||
const errorHeader = ref('No header');
|
||||
|
||||
listen<{ message: string; header: string }>('invoke-error', (event) => {
|
||||
errorVisible.value = true;
|
||||
errorMessage.value = event.payload.message;
|
||||
errorHeader.value = event.payload.header;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main :class="client.scaleFactor === 's' ? 'main-scale-s' : client.scaleFactor === 'm' ? 'main-scale-m' : client.scaleFactor === 'l' ? 'main-scale-l' : 'main-scale-xl'">
|
||||
<main
|
||||
:class="
|
||||
client.scaleFactor === 's'
|
||||
? 'main-scale-s'
|
||||
: client.scaleFactor === 'm'
|
||||
? 'main-scale-m'
|
||||
: client.scaleFactor === 'l'
|
||||
? 'main-scale-l'
|
||||
: 'main-scale-xl'
|
||||
"
|
||||
>
|
||||
<Dialog
|
||||
modal
|
||||
:visible="errorVisible"
|
||||
:closable="false /*this shit doesn't work */"
|
||||
:header="errorHeader"
|
||||
:style="{ width: '50vw' }"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
{{ errorMessage }}
|
||||
<Button
|
||||
class="m-auto"
|
||||
label="A sad state of affairs"
|
||||
@click="errorVisible = false"
|
||||
/>
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
<Tabs
|
||||
lazy
|
||||
:value="currentTab"
|
||||
v-on:update:value="(value) => { currentTab = value; }"
|
||||
v-on:update:value="
|
||||
(value) => {
|
||||
currentTab = value;
|
||||
}
|
||||
"
|
||||
class="h-screen"
|
||||
>
|
||||
<div class="fixed w-full flex z-100">
|
||||
<TabList class="grow" :show-navigators="false">
|
||||
<Tab :value="3"
|
||||
><div class="pi pi-users"></div
|
||||
><div class="pi pi-users" v-tooltip="'Profiles'"></div
|
||||
></Tab>
|
||||
<Tab :disabled="isProfileDisabled" :value="0"
|
||||
><div class="pi pi-box"></div
|
||||
><div
|
||||
class="pi pi-box"
|
||||
v-tooltip="'Installed packages'"
|
||||
></div
|
||||
></Tab>
|
||||
<Tab v-if="prf.current?.meta.game === 'chunithm'" :value="4"
|
||||
><div class="pi pi-ticket"></div
|
||||
><div class="pi pi-ticket" v-tooltip="'Patches'"></div
|
||||
></Tab>
|
||||
<Tab
|
||||
v-if="pkg.networkStatus === 'online'"
|
||||
:disabled="isProfileDisabled"
|
||||
:value="1"
|
||||
><div class="pi pi-download"></div
|
||||
><div
|
||||
class="pi pi-download"
|
||||
v-tooltip="'Package store'"
|
||||
></div
|
||||
></Tab>
|
||||
<Tab :disabled="isProfileDisabled" :value="2"
|
||||
><div class="pi pi-cog"></div
|
||||
><div class="pi pi-cog" v-tooltip="'Settings'"></div
|
||||
></Tab>
|
||||
|
||||
<div class="grow"></div>
|
||||
@ -96,7 +149,7 @@ onMounted(async () => {
|
||||
</InputIcon>
|
||||
<InputText
|
||||
v-if="currentTab === 2"
|
||||
style="min-width: 0; width: 25dvw;"
|
||||
style="min-width: 0; width: 25dvw"
|
||||
class="self-center"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
@ -104,7 +157,7 @@ onMounted(async () => {
|
||||
/>
|
||||
<InputText
|
||||
v-else
|
||||
style="min-width: 0; width: 25dvw;"
|
||||
style="min-width: 0; width: 25dvw"
|
||||
class="self-center"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
@ -119,14 +172,20 @@ onMounted(async () => {
|
||||
:disabled="true"
|
||||
/>
|
||||
<Button
|
||||
v-if="pkg.networkStatus === 'offline' && !client.offlineMode"
|
||||
v-if="
|
||||
pkg.networkStatus === 'offline' &&
|
||||
!client.offlineMode
|
||||
"
|
||||
class="shrink self-center"
|
||||
icon="pi pi-sync"
|
||||
size="small"
|
||||
@click="pkg.fetch(false)"
|
||||
/>
|
||||
<Button
|
||||
v-if="pkg.networkStatus === 'online' && pkg.hasAvailableUpdates"
|
||||
v-if="
|
||||
pkg.networkStatus === 'online' &&
|
||||
pkg.hasAvailableUpdates
|
||||
"
|
||||
icon="pi pi-download"
|
||||
label="UPDATE ALL"
|
||||
size="small"
|
||||
@ -161,8 +220,13 @@ onMounted(async () => {
|
||||
</footer>
|
||||
</TabPanel>
|
||||
<TabPanel :value="4">
|
||||
CHUNITHM patches are not yet implemented.<br />Use
|
||||
<a href=https://patcher.two-torial.xyz/ target="_blank" style="text-decoration: underline;">patcher.two-torial.xyz</a>
|
||||
CHUNITHM patches are not implemented yet.<br />Use
|
||||
<a
|
||||
href="https://patcher.two-torial.xyz/"
|
||||
target="_blank"
|
||||
style="text-decoration: underline"
|
||||
>patcher.two-torial.xyz</a
|
||||
>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
<div v-if="currentTab === 5 || currentTab === 3">
|
||||
@ -196,19 +260,19 @@ body {
|
||||
}
|
||||
|
||||
.main-scale-s {
|
||||
zoom: 1.0
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
.main-scale-m {
|
||||
zoom: 1.25
|
||||
zoom: 1.25;
|
||||
}
|
||||
|
||||
.main-scale-l {
|
||||
zoom: 1.4
|
||||
zoom: 1.4;
|
||||
}
|
||||
|
||||
.main-scale-xl {
|
||||
zoom: 1.7
|
||||
zoom: 1.7;
|
||||
}
|
||||
|
||||
.p-tablist {
|
||||
|
@ -1,7 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import Button from 'primevue/button';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { usePrfStore } from '../stores';
|
||||
|
||||
const props = defineProps({
|
||||
placeholder: String,
|
||||
@ -12,10 +14,25 @@ const props = defineProps({
|
||||
callback: Function,
|
||||
});
|
||||
|
||||
const prf = usePrfStore();
|
||||
|
||||
const filePick = async () => {
|
||||
const exePath = prf.current?.data.sgt.target;
|
||||
let defaultPath: string | undefined;
|
||||
if (
|
||||
exePath !== undefined &&
|
||||
exePath.length > 0 &&
|
||||
props.value !== undefined &&
|
||||
!(await path.isAbsolute(props.value))
|
||||
) {
|
||||
defaultPath = await path.join(exePath, '..');
|
||||
defaultPath = await path.join(defaultPath, props.value);
|
||||
defaultPath = await path.join(defaultPath, '..');
|
||||
}
|
||||
const res = await open({
|
||||
multiple: false,
|
||||
directory: props.directory,
|
||||
defaultPath,
|
||||
filters:
|
||||
props.promptname && props.extension
|
||||
? [
|
||||
@ -28,7 +45,7 @@ const filePick = async () => {
|
||||
});
|
||||
if (res != null && props.callback !== undefined) {
|
||||
props.callback(res);
|
||||
/*path.relative(cfgs.current?.data.exe_dir ?? '', res) */
|
||||
/*path.relative(prf.current?.data.sgt.target ?? '', res) */
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -7,6 +7,9 @@ const prf = usePrfStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="prf.list.length === 0">
|
||||
Welcome to STARTLINER! Start by creating a profile.
|
||||
</div>
|
||||
<div class="mt-4 flex flex-row flex-wrap align-middle gap-4">
|
||||
<Button
|
||||
label="O.N.G.E.K.I. profile"
|
||||
|
@ -45,7 +45,7 @@ const updatesModel = computed({
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Offline mode"
|
||||
tooltip="Disables the package store. Applies after a restart"
|
||||
tooltip="Disables the package store. Requires a restart."
|
||||
>
|
||||
<ToggleSwitch v-model="offlineModel" />
|
||||
</OptionRow>
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
InvokeOptions,
|
||||
invoke as real_invoke,
|
||||
} from '@tauri-apps/api/core';
|
||||
import { message } from '@tauri-apps/plugin-dialog';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
|
||||
export const invoke = async <T>(
|
||||
cmd: string,
|
||||
@ -14,9 +14,9 @@ export const invoke = async <T>(
|
||||
return await real_invoke(cmd, args, options);
|
||||
} catch (e: unknown) {
|
||||
if (typeof e === 'string') {
|
||||
await message(`${cmd}: ${e}`, {
|
||||
title: `Error`,
|
||||
kind: 'error',
|
||||
emit('invoke-error', {
|
||||
message: e,
|
||||
header: `${cmd} failed`,
|
||||
});
|
||||
} else {
|
||||
console.error(`Unresolved error: ${e}`);
|
||||
|
Reference in New Issue
Block a user