EZPPLauncher/src/pages/Loading.svelte
HorizonCode 651592c333 feat: Refactor API interactions and enhance user settings management
- Updated ezpp API to include user info retrieval and improved error handling.
- Introduced new writable stores for current user info and loading states.
- Added gamemode enums and utility functions for better gamemode handling.
- Refactored global state management to use consistent naming conventions.
- Enhanced loading and login components to provide better user feedback.
- Updated user settings to include preferred mode and type.
- Improved layout and page components for better state management and user experience.
2025-07-03 11:46:50 +02:00

192 lines
5.6 KiB
Svelte

<script lang="ts">
import Logo from '$assets/logo.png';
import { estimateRefreshRate } from '@/displayUtils';
import { beatmapSets, currentLoadingInfo, currentView, firstStartup } from '@/global';
import {
cursorSmoothness,
osuInstallationPath,
preferredMode,
preferredType,
userSettings,
} from '@/userSettings';
import { animate, utils } from 'animejs';
import { onMount } from 'svelte';
import SetupWizard from './SetupWizard.svelte';
import Launch from './Launch.svelte';
import { currentUser, userAuth } from '@/userAuthentication';
import { ezppfarm } from '@/api/ezpp';
import { toast } from 'svelte-sonner';
import { currentUserInfo } from '@/data';
import { invoke } from '@tauri-apps/api/core';
let ezppLogo: HTMLImageElement;
let spinnerCircle: SVGCircleElement;
let animateInterval: number | undefined;
//TODO: use this to check for updates upon launch
const doBPMAnimation = () => {
if (animateInterval) return;
animateInterval = window.setInterval(async () => {
animate(ezppLogo, {
scale: 1.1,
duration: 900,
ease: (t: number) => Math.pow(2, -5 * t) * Math.sin((t - 0.075) * 20.94) + 1 - 0.0005 * t,
onComplete: () => {},
});
await new Promise((resolve) => setTimeout(resolve, 200));
animate(ezppLogo, {
scale: 1,
duration: 900,
ease: (t: number) => (t - 1) ** 7 + 1,
onComplete: () => {},
});
}, 450);
};
const calculateCursorSmoothness = async () => {
const refreshRate = await estimateRefreshRate();
const hzMin = 60;
const hzMax = 144;
const durationMin = 70;
const durationMax = 180;
const duration =
durationMin + ((refreshRate - hzMin) / (hzMax - hzMin)) * (durationMax - durationMin);
cursorSmoothness.set(Math.round(duration));
};
const prepare = async () => {
await calculateCursorSmoothness();
const username = $userAuth.value('username').get('');
const password = $userAuth.value('password').get('');
if (username.length > 0 && password.length > 0) {
currentLoadingInfo.set('Logging in...');
try {
const loginResult = await ezppfarm.login(username, password);
if (loginResult && loginResult.user) {
toast.success('Login successful!', {
description: `Welcome back, ${loginResult.user.name}!`,
});
currentUser.set(loginResult.user);
} else {
toast.error('Login failed!', {
description: 'Please check your username and password.',
});
}
} catch {
toast.error('Server error occurred during login.', {
description: 'There was an issue connecting to the server. Please try again later.',
});
}
}
if ($currentUser) {
currentLoadingInfo.set('Loading user info...');
const userInfo = await ezppfarm.getUserInfo($currentUser.id);
if (userInfo) {
currentUserInfo.set(userInfo.player);
preferredMode.set(userInfo.player.info.preferred_mode);
preferredType.set(userInfo.player.info.preferred_type);
}
}
if (!$firstStartup) {
currentLoadingInfo.set('Checking osu installation path...');
const validFolder: boolean = await invoke('valid_osu_folder', {
folder: $osuInstallationPath,
});
if (!validFolder) {
osuInstallationPath.set('');
$userSettings.value('osu_installation_path').del();
await $userSettings.save();
toast.error('Oops...', {
description: 'Your previously set osu! installation path seems to be invalid.',
});
} else {
currentLoadingInfo.set('Counting beatmapsets...');
const beatmapSetCount: number | null = await invoke('get_beatmapsets_count', {
folder: $osuInstallationPath,
});
if (beatmapSetCount) {
beatmapSets.set(beatmapSetCount);
}
}
}
animate(ezppLogo, {
opacity: [1, 0],
scale: [1, 1.05],
duration: 1000,
ease: (t: number) => (t - 1) ** 7 + 1,
onComplete: () => {},
});
animate(spinnerCircle, {
opacity: 0,
duration: 1000,
ease: (t: number) => (t - 1) ** 7 + 1,
onComplete: () => {},
});
setTimeout(() => {
if ($firstStartup) currentView.set(SetupWizard);
else currentView.set(Launch);
}, 250);
};
onMount(() => {
animate(ezppLogo, {
opacity: [0, 1],
scale: [0.95, 1],
duration: 900,
ease: (t: number) => (t - 1) ** 7 + 1,
onComplete: doBPMAnimation,
});
animate(spinnerCircle, {
strokeDashoffset: [0, -565],
duration: 1800,
easing: 'linear',
loop: true,
});
prepare();
return () => {
window.clearInterval(animateInterval);
utils.remove(spinnerCircle);
};
});
</script>
<div class="flex flex-col items-center justify-center mt-[50px] h-[calc(100vh-50px)] w-full">
<div class="relative w-80 h-80 flex items-center justify-center">
<svg
class="absolute top-0 left-0 w-full h-full animate-spin"
style="animation-duration: 5s;"
viewBox="0 0 208 208"
>
<circle
cx="104"
cy="104"
r="90"
fill="none"
stroke="#ff0098"
stroke-width="8"
stroke-linecap="round"
stroke-dasharray="180 385"
stroke-dashoffset="0"
bind:this={spinnerCircle}
/>
</svg>
<img
src={Logo}
alt="EZPPLauncher Logo"
class="w-52 h-52 mb-2 relative z-10"
bind:this={ezppLogo}
/>
</div>
<span class="text-theme-200 font-semibold">{$currentLoadingInfo}</span>
</div>