feat: remember current tab

This commit is contained in:
2025-04-27 05:56:04 +00:00
parent bf4c06ee2d
commit 6cc7a537b6
10 changed files with 86 additions and 41 deletions

View File

@ -1,3 +1,11 @@
## 0.16.0
- Fixed the clear cache button not working
- Fixed Linux builds
- Moved the store tab to the left
- STARTLINER now remembers the recently open tab and re-opens it on the next session
- Added "Beta" to the title as STARTLINER is approaching feature-completeness
## 0.15.0
- Added internationalization

View File

@ -336,7 +336,7 @@ async fn update(app: tauri::AppHandle) -> tauri_plugin_updater::Result<()> {
fn open_window(apph: AppHandle) -> anyhow::Result<()> {
let config = apph.config().clone();
tauri::WebviewWindowBuilder::new(&apph, "main", tauri::WebviewUrl::App("index.html".into()))
.title(format!("STARTLINER {}", config.version.unwrap_or_default()))
.title(format!("STARTLINER {} Beta", config.version.unwrap_or_default()))
.inner_size(900f64, 600f64)
.min_inner_size(900f64, 600f64)
.build()?;

View File

@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "STARTLINER",
"version": "0.15.0",
"version": "0.16.0",
"identifier": "zip.patafour.startliner",
"build": {
"beforeDevCommand": "bun run dev",

View File

@ -20,7 +20,6 @@ import OptionList from './OptionList.vue';
import PatchList from './PatchList.vue';
import ProfileList from './ProfileList.vue';
import StartButton from './StartButton.vue';
import { invoke } from '../invoke';
import {
useClientStore,
useGeneralStore,
@ -36,10 +35,10 @@ const prf = usePrfStore();
const general = useGeneralStore();
const client = useClientStore();
client.load();
pkg.setupListeners();
const currentTab: Ref<'users' | 'loc' | 'patches' | 'rmt' | 'cfg' | 'info'> =
ref('users');
const pkgSearchTerm = ref('');
const isProfileDisabled = computed(() => prf.current === null);
@ -60,7 +59,6 @@ onMounted(async () => {
await Promise.all([prf.reloadList(), prf.reload()]);
if (prf.current !== null) {
currentTab.value = 'loc';
await pkg.reloadAll();
}
@ -205,10 +203,11 @@ listen<DownloadingStatus>('download-progress', (event) => {
<Tabs
lazy
:value="currentTab"
:value="client.currentTab"
v-on:update:value="
(value) => {
currentTab = value as any;
client.currentTab = value as string;
client.save();
}
"
class="h-screen"
@ -216,6 +215,13 @@ listen<DownloadingStatus>('download-progress', (event) => {
<div class="fixed w-full flex z-100">
<TabList class="grow" :show-navigators="false">
<Tab value="users"><div class="pi pi-home"></div></Tab>
<Tab
:disabled="
isProfileDisabled || pkg.networkStatus !== 'online'
"
value="rmt"
><div class="pi pi-download"></div
></Tab>
<Tab :disabled="isProfileDisabled" value="loc"
><div class="pi pi-box"></div
></Tab>
@ -224,13 +230,7 @@ listen<DownloadingStatus>('download-progress', (event) => {
value="patches"
><div class="pi pi-ticket"></div
></Tab>
<Tab
:disabled="
isProfileDisabled || pkg.networkStatus !== 'online'
"
value="rmt"
><div class="pi pi-download"></div
></Tab>
<Tab :disabled="isProfileDisabled" value="cfg"
><div class="pi pi-cog"></div
></Tab>
@ -243,13 +243,17 @@ listen<DownloadingStatus>('download-progress', (event) => {
<div class="flex gap-4">
<div
class="flex"
v-if="['loc', 'rmt', 'cfg'].includes(currentTab)"
v-if="
['loc', 'rmt', 'cfg'].includes(
client.currentTab
)
"
>
<InputIcon class="self-center mr-2">
<i class="pi pi-search" />
</InputIcon>
<InputText
v-if="currentTab === 'cfg'"
v-if="client.currentTab === 'cfg'"
style="min-width: 0; width: 25dvw"
class="self-center"
size="small"
@ -342,7 +346,12 @@ listen<DownloadingStatus>('download-progress', (event) => {
<InfoPage />
</TabPanel>
</TabPanels>
<div v-if="currentTab === 'users' || currentTab === 'info'">
<div
v-if="
client.currentTab === 'users' ||
client.currentTab === 'info'
"
>
<img
v-if="prf.current?.meta.game === 'ongeki'"
src="/sticker-ongeki.svg"

View File

@ -1,5 +1,6 @@
<script setup lang="ts">
import { Ref, ref } from 'vue';
// import Select from 'primevue/select';
import * as path from '@tauri-apps/api/path';
import OptionCategory from './OptionCategory.vue';
import PatchEntry from './PatchEntry.vue';
@ -32,8 +33,6 @@ invoke('list_patches', { target: prf.current!.data.sgt.target }).then(
target: amd,
})) as Patch[];
})();
const errorMessage = t('patch.noneFound');
</script>
<template>
@ -49,7 +48,7 @@ const errorMessage = t('patch.noneFound');
/>
<div v-if="gamePatches === null">{{ t('patch.loading') }}</div>
<div v-if="gamePatches !== null && gamePatches.length === 0">
{{ errorMessage }}
{{ t('patch.noneFound') }}
</div>
</OptionCategory>
<OptionCategory title="amdaemon.exe" always-found>
@ -60,7 +59,20 @@ const errorMessage = t('patch.noneFound');
/>
<div v-if="gamePatches === null">Loading...</div>
<div v-if="amdPatches !== null && amdPatches.length === 0">
{{ errorMessage }}
{{ t('patch.noneFound') }}
<!-- <br />
<Select
class="mt-3"
style="width: 400px"
:options="[
{},
{},
]"
:placeholder="t('patch.forceLoad')"
size="small"
option-label="title"
option-value="value"
></Select> -->
</div>
</OptionCategory>
</template>

View File

@ -73,10 +73,12 @@ const promptDeleteProfile = async () => {
const dataExists = ref(false);
path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
async (p) => {
dataExists.value = await invoke('file_exists', { path: p });
}
general.dataDir.then((dataDir) =>
path
.join(dataDir, `profile-${props.p!.game}-${props.p!.name}`)
.then(async (p) => {
dataExists.value = await invoke('file_exists', { path: p });
})
);
</script>
@ -145,11 +147,15 @@ path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
class="self-center"
style="width: 2rem; height: 2rem"
@click="
path
.join(general.configDir, `profile-${p!.game}-${p!.name}`)
.then(async (path) => {
await invoke('open_file', { path });
})
async () =>
path
.join(
await general.configDir,
`profile-${p!.game}-${p!.name}`
)
.then(async (path) => {
await invoke('open_file', { path });
})
"
/>
<Button
@ -162,11 +168,15 @@ path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
class="self-center"
style="width: 2rem; height: 2rem"
@click="
path
.join(general.dataDir, `profile-${p!.game}-${p!.name}`)
.then(async (path) => {
await invoke('open_file', { path });
})
async () =>
path
.join(
await general.dataDir,
`profile-${p!.game}-${p!.name}`
)
.then(async (path) => {
await invoke('open_file', { path });
})
"
/>
</div>

View File

@ -194,9 +194,7 @@ const tryStart = () => {
}
"
/>
<Lazy>
<ContextMenu ref="menu" :model="menuItems" />
</Lazy>
<ContextMenu ref="menu" :model="menuItems" />
<Button
v-if="startStatus === 'ready'"
v-tooltip="disabledTooltip"

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { Ref, computed, onMounted, ref } from 'vue';
import { Ref, computed, ref } from 'vue';
import InputNumber from 'primevue/inputnumber';
import Select from 'primevue/select';
import SelectButton from 'primevue/selectbutton';

View File

@ -51,6 +51,7 @@ export default {
loading: 'Loading...',
noneFound:
"No compatible patches found. Make sure you're using unpacked and unpatched files.",
forceLoad: 'Force load',
// Example patch name override
'standard-no-encryption': 'No encryption',
},

View File

@ -322,7 +322,7 @@ export const usePrfStore = defineStore('prf', () => {
const generalStore = useGeneralStore();
const configDir = computed(async () => {
return await path.join(
return path.join(
await generalStore.configDir,
`profile-${current.value?.meta.game}-${current.value?.meta.name}`
);
@ -374,6 +374,7 @@ export const useClientStore = defineStore('client', () => {
const theme: Ref<'light' | 'dark' | 'system'> = ref('system');
const onboarded: Ref<Game[]> = ref([]);
const locale: Ref<Locale> = ref('en');
const currentTab: Ref<string> = ref('');
const _scaleValue = (value: ScaleType) =>
value === 's' ? 1 : value === 'm' ? 1.25 : value === 'l' ? 1.5 : 2;
@ -440,6 +441,10 @@ export const useClientStore = defineStore('client', () => {
if (input.locale) {
locale.value = input.locale;
}
if (input.currentTab) {
currentTab.value = input.currentTab;
}
await setLocale(locale.value);
await setTheme(theme.value);
} catch (e) {
@ -478,6 +483,7 @@ export const useClientStore = defineStore('client', () => {
theme: theme.value,
onboarded: onboarded.value,
locale: locale.value,
currentTab: currentTab.value,
})
);
};
@ -553,6 +559,7 @@ export const useClientStore = defineStore('client', () => {
locale,
timeout,
scaleModel,
currentTab,
_scaleValue,
scaleValue,
load,