import { Ref, computed, ref, watchEffect } from 'vue'; import { defineStore } from 'pinia'; import { listen } from '@tauri-apps/api/event'; import * as path from '@tauri-apps/api/path'; import { invoke } from './invoke'; import { Dirs, Game, Package, Profile, ProfileMeta } from './types'; import { changePrimaryColor, pkgKey } from './util'; type InstallStatus = { pkg: string; }; export const useGeneralStore = defineStore('general', () => { const dirs: Ref = ref(null); const configDir = computed(() => { if (dirs.value === null) { throw new Error('Invalid directory access'); } return dirs.value.config_dir; }); const dataDir = computed(() => { if (dirs.value === null) { throw new Error('Invalid directory access'); } return dirs.value.data_dir; }); const cacheDir = computed(() => { if (dirs.value === null) { throw new Error('Invalid directory access'); } return dirs.value.cache_dir; }); return { dirs, configDir, dataDir, cacheDir }; }); export const usePkgStore = defineStore('pkg', { state: (): { pkg: { [key: string]: Package } } => { return { pkg: {}, }; }, getters: { fromDepString: (state) => (str: string) => state.pkg[str] ?? null, fromName: (state) => (namespace: string, name: string) => state.pkg[`${namespace}-${name}`] ?? null, all: (state) => Object.values(state), allLocal: (state) => Object.values(state.pkg).filter((p) => p.loc), allRemote: (state) => Object.values(state.pkg).filter((p) => p.rmt), }, actions: { setupListeners() { listen('install-start', async (ev) => { const key = ev.payload.pkg; await this.reload(key); this.pkg[key].js.busy = true; }); listen('install-end', async (ev) => { const key = ev.payload.pkg; await this.reload(key); this.pkg[key].js.busy = false; }); }, async reloadAll() { await invoke('reload_all_packages'); const data = (await invoke('get_all_packages')) as { [key: string]: Package; }; for (const [k, v] of Object.entries(data)) { this.reloadWith(k, v); } }, async reload(pkgOrKey: string | Package) { const key = typeof pkgOrKey === 'string' ? pkgOrKey : pkgKey(pkgOrKey); const pkg: Package = await invoke('get_package', { key, }); this.reloadWith(key, pkg); }, async reloadWith(key: string, pkg: Package) { if (this.pkg[key] === undefined) { this.pkg[key] = { js: { busy: false } } as Package; } else { this.pkg[key].loc = null; this.pkg[key].rmt = null; } Object.assign(this.pkg[key], pkg); }, async fetch() { await invoke('fetch_listings'); await this.reloadAll(); }, }, }); export const usePrfStore = defineStore('prf', () => { const current: Ref = ref(null); const list: Ref = ref([]); const isPkgEnabled = (pkg: Package | undefined) => computed( () => pkg !== undefined && current.value !== null && current.value?.mods.includes(pkgKey(pkg)) ); const reload = async () => { const p = (await invoke('get_current_profile')) as any; if (p != null && 'OngekiProfile' in p) { current.value = { ...p.OngekiProfile, game: 'ongeki' }; } else { current.value = null; } if (current.value !== null) { changePrimaryColor(current.value.game); } else { changePrimaryColor(null); } }; const create = async (game: Game) => { try { await invoke('init_profile', { game, name: 'new-profile', }); await reload(); await reloadList(); } catch (e) { current.value = null; } if (current.value !== null) { const pkgs = usePkgStore(); pkgs.reloadAll(); } }; const rename = async (profile: ProfileMeta, name: string) => { await invoke('rename_profile', { profile, name, }); if ( current.value?.game === profile.game && current.value.name === profile.name ) { current.value.name = name; } await reloadList(); }; const switchTo = async (game: Game, name: string) => { await invoke('load_profile', { game, name }); await reload(); if (current.value !== null) { const pkgs = usePkgStore(); pkgs.reloadAll(); } }; const reloadList = async () => { list.value = (await invoke('list_profiles')) as ProfileMeta[]; }; const togglePkg = async (pkg: Package | undefined, enable: boolean) => { if (pkg === undefined) { return; } await invoke('toggle_package', { key: pkgKey(pkg), enable }); await reload(); }; const generalStore = useGeneralStore(); const configDir = computed(async () => { return await path.join( generalStore.configDir, `profile-${current.value?.game}-${current.value?.name}` ); }); listen('install-end', async () => { await reload(); }); watchEffect(async () => { if (current.value !== null) { await invoke('save_current_profile', { profile: { OngekiProfile: current.value }, }); } }); return { current, list, isPkgEnabled, reload, create, rename, switchTo, reloadList, togglePkg, configDir, }; });