Compare commits
7 Commits
3.1.2
...
0b9d6373bf
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b9d6373bf | |||
| 295c1424c9 | |||
| 0e12a801d2 | |||
| cf86dba5c4 | |||
| 540c653399 | |||
| c9b8d9f599 | |||
| 49665d94bc |
Generated
+1
@@ -1011,6 +1011,7 @@ version = "3.1.2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"discord-rich-presence",
|
"discord-rich-presence",
|
||||||
|
"futures-util",
|
||||||
"hardware-id",
|
"hardware-id",
|
||||||
"md5",
|
"md5",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|||||||
@@ -32,15 +32,16 @@ reqwest = { version = "0.13.1", features = ["json", "stream", "query"] }
|
|||||||
md5 = "0.8.0"
|
md5 = "0.8.0"
|
||||||
tokio = { version = "1.48.0", features = ["full"] }
|
tokio = { version = "1.48.0", features = ["full"] }
|
||||||
open = "5.3.3"
|
open = "5.3.3"
|
||||||
windows-sys = "0.61.2"
|
|
||||||
discord-rich-presence = "1.0.0"
|
discord-rich-presence = "1.0.0"
|
||||||
once_cell = "1.21.3"
|
once_cell = "1.21.3"
|
||||||
|
futures-util = "0.3"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winreg = "0.55.0"
|
winreg = "0.55.0"
|
||||||
winapi = { version = "0.3", features = ["winuser", "wincrypt", "memoryapi", "winbase", "dpapi"] }
|
winapi = { version = "0.3", features = ["winuser", "wincrypt", "memoryapi", "winbase", "dpapi"] }
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
widestring = "1.2.1"
|
widestring = "1.2.1"
|
||||||
|
windows-sys = "0.61.2"
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
tauri-plugin-single-instance = "2.3.6"
|
tauri-plugin-single-instance = "2.3.6"
|
||||||
|
|||||||
+29
-11
@@ -2,6 +2,7 @@ use discord_rich_presence::{
|
|||||||
DiscordIpc, DiscordIpcClient,
|
DiscordIpc, DiscordIpcClient,
|
||||||
activity::{Activity, Assets, Button, Timestamps},
|
activity::{Activity, Assets, Button, Timestamps},
|
||||||
};
|
};
|
||||||
|
use futures_util::future::BoxFuture;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::sync::Mutex as StdMutex;
|
use std::sync::Mutex as StdMutex;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
@@ -24,6 +25,7 @@ enum PresenceCommand {
|
|||||||
Disconnect(oneshot::Sender<()>),
|
Disconnect(oneshot::Sender<()>),
|
||||||
UpdateData(PresenceData),
|
UpdateData(PresenceData),
|
||||||
IsConnected(oneshot::Sender<bool>),
|
IsConnected(oneshot::Sender<bool>),
|
||||||
|
Tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PresenceActor {
|
struct PresenceActor {
|
||||||
@@ -58,7 +60,7 @@ impl PresenceActor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&mut self) {
|
async fn run(&mut self) {
|
||||||
let mut update_interval = interval(Duration::from_millis(2500));
|
let mut update_interval = interval(Duration::from_secs(5));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
@@ -74,18 +76,22 @@ impl PresenceActor {
|
|||||||
PresenceCommand::IsConnected(responder) => {
|
PresenceCommand::IsConnected(responder) => {
|
||||||
let _ = responder.send(self.client.is_some());
|
let _ = responder.send(self.client.is_some());
|
||||||
}
|
}
|
||||||
}
|
PresenceCommand::Tick => {
|
||||||
}
|
|
||||||
_ = update_interval.tick() => {
|
|
||||||
if self.client.is_some() {
|
if self.client.is_some() {
|
||||||
self.handle_update().await;
|
self.handle_update().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ = update_interval.tick() => {
|
||||||
|
let _ = PRESENCE_TX.send(PresenceCommand::Tick).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connect(&mut self, responder: oneshot::Sender<bool>) {
|
fn handle_connect(&mut self, responder: oneshot::Sender<bool>) -> BoxFuture<'_, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
if self.client.is_some() {
|
if self.client.is_some() {
|
||||||
let _ = responder.send(true);
|
let _ = responder.send(true);
|
||||||
return;
|
return;
|
||||||
@@ -101,11 +107,21 @@ impl PresenceActor {
|
|||||||
let _ = responder.send(true);
|
let _ = responder.send(true);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to create Discord client: {:?}", e);
|
eprintln!("Failed to connect to Discord: {:?}. Retrying in 5s...", e);
|
||||||
|
let tx = PRESENCE_TX.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||||
|
let (resp_tx, _) = oneshot::channel();
|
||||||
|
let _ = tx.send(PresenceCommand::Connect(resp_tx)).await;
|
||||||
|
});
|
||||||
|
|
||||||
|
if !responder.is_closed() {
|
||||||
let _ = responder.send(false);
|
let _ = responder.send(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async fn handle_disconnect(&mut self, responder: oneshot::Sender<()>) {
|
async fn handle_disconnect(&mut self, responder: oneshot::Sender<()>) {
|
||||||
if let Some(mut client) = self.client.take() {
|
if let Some(mut client) = self.client.take() {
|
||||||
@@ -143,12 +159,14 @@ impl PresenceActor {
|
|||||||
Button::new("Join EZPPFarm", "https://ez-pp.farm/discord"),
|
Button::new("Join EZPPFarm", "https://ez-pp.farm/discord"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if let Err(e) = client.set_activity(activity).map_err(|e| e.to_string()) {
|
if let Err(e) = client.set_activity(activity) {
|
||||||
eprintln!("Failed to set activity, disconnecting: {:?}", e);
|
eprintln!("Failed to set activity, disconnecting: {:?}", e);
|
||||||
if let Some(mut client) = self.client.take() {
|
self.client = None;
|
||||||
let _ = client.clear_activity();
|
|
||||||
let _ = client.close();
|
let (tx, _) = oneshot::channel();
|
||||||
}
|
self.handle_connect(tx).await;
|
||||||
|
} else {
|
||||||
|
println!("Actor: Presence updated successfully.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
@@ -1,5 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Logo from '$assets/logo.png';
|
import Logo from '$assets/logo.png';
|
||||||
|
import { reduceAnimations } from '@/userSettings';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
//TODO: maybe dynamic background images fetched from ezpp?
|
//TODO: maybe dynamic background images fetched from ezpp?
|
||||||
|
|
||||||
@@ -37,15 +39,15 @@
|
|||||||
<div
|
<div
|
||||||
class="relative h-full w-full from-0% to-90% bg-gradient-to-b from-transparent to-black z-50"
|
class="relative h-full w-full from-0% to-90% bg-gradient-to-b from-transparent to-black z-50"
|
||||||
></div>
|
></div>
|
||||||
{#each streaks as s}
|
{#each streaks as s, index (index)}
|
||||||
<div
|
<div
|
||||||
class="streak drop-shadow-lg"
|
class="streak drop-shadow-lg transition-opacity duration-1000"
|
||||||
style="
|
style="
|
||||||
width:{s.width}px;
|
width:{s.width}px;
|
||||||
height:{s.height}px;
|
height:{s.height}px;
|
||||||
left:{s.x}%;
|
left:{s.x}%;
|
||||||
top:{s.y}%;
|
top:{s.y}%;
|
||||||
opacity:{s.opacity};
|
opacity:{$reduceAnimations ? 0 : s.opacity};
|
||||||
animation-duration:{s.duration}s;
|
animation-duration:{s.duration}s;
|
||||||
animation-delay:-{s.delay}s;
|
animation-delay:-{s.delay}s;
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import NyanCat from '$assets/nyan-cat.gif';
|
||||||
|
import { reduceAnimations } from '@/userSettings';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
|
//TODO: maybe dynamic background images fetched from ezpp?
|
||||||
|
|
||||||
|
const COUNT = 18;
|
||||||
|
|
||||||
|
function rand(min: number, max: number) {
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
const streaks = Array.from({ length: COUNT })
|
||||||
|
.map((_, i) => {
|
||||||
|
const depth = rand(0, 2);
|
||||||
|
|
||||||
|
const scale = 0.6 + depth * 0.8;
|
||||||
|
const speed = 0.4 + depth * 1.35;
|
||||||
|
|
||||||
|
const distance = 150;
|
||||||
|
const duration = distance / speed;
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: 290 * scale,
|
||||||
|
height: 140 * scale,
|
||||||
|
x: (i / COUNT) * 200 - 50,
|
||||||
|
y: ((i * 137.5) % 100) - 20,
|
||||||
|
opacity: 0.25 + depth * 0.65,
|
||||||
|
duration,
|
||||||
|
delay: rand(0, duration),
|
||||||
|
scale,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.scale - b.scale);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="absolute bg blur-[2px]">
|
||||||
|
<div
|
||||||
|
class="relative h-full w-full from-0% to-90% bg-gradient-to-b from-transparent to-black z-50"
|
||||||
|
></div>
|
||||||
|
{#each streaks as s, index (index)}
|
||||||
|
<div
|
||||||
|
class="streak drop-shadow-lg transition-opacity duration-1000"
|
||||||
|
style="
|
||||||
|
width:{s.width}px;
|
||||||
|
height:{s.height}px;
|
||||||
|
left:{s.x}%;
|
||||||
|
top:{s.y}%;
|
||||||
|
opacity:{$reduceAnimations ? 0 : s.opacity};
|
||||||
|
animation-duration:{s.duration}s;
|
||||||
|
animation-delay:-{s.delay}s;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={NyanCat}
|
||||||
|
alt="nyan cat"
|
||||||
|
class="w-full h-full"
|
||||||
|
style="opacity:{$reduceAnimations ? 0 : s.opacity};"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.bg {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--color-blue-800) 0%,
|
||||||
|
var(--color-blue-600) 40%,
|
||||||
|
var(--color-blue-900) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.streak {
|
||||||
|
position: absolute;
|
||||||
|
animation: move linear infinite;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes move {
|
||||||
|
from {
|
||||||
|
transform: translate(-250vw, 0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translate(250vw, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { launcherVersion } from '@/global';
|
import { launcherVersion } from '@/global';
|
||||||
import Badge from '../badge/badge.svelte';
|
import Badge from '../badge/badge.svelte';
|
||||||
|
import { reduceAnimations } from '@/userSettings';
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const appWindow = getCurrentWindow();
|
const appWindow = getCurrentWindow();
|
||||||
@@ -20,22 +21,39 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div data-tauri-drag-region class="titlebar z-[100]">
|
<div data-tauri-drag-region class="titlebar z-[100]">
|
||||||
<div class="titlebar-button rounded transition-colors duration-75" id="titlebar-minimize">
|
<div class="relative flex items-center justify-center p-1 group" id="titlebar-minimize">
|
||||||
<Minimize size={14} />
|
<div
|
||||||
|
class="absolute inset-0 bg-background rounded
|
||||||
|
scale-50 opacity-0
|
||||||
|
group-hover:opacity-100
|
||||||
|
group-hover:scale-100
|
||||||
|
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
|
||||||
|
origin-center"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<Minimize class="z-10 pointer-events-none" size={14} />
|
||||||
</div>
|
</div>
|
||||||
<div class="titlebar-button close rounded transition-colors duration-75" id="titlebar-close">
|
<div class="relative flex items-center justify-center p-1 group" id="titlebar-close">
|
||||||
<Close size={14} />
|
<div
|
||||||
|
class="absolute inset-0 bg-red-500 rounded
|
||||||
|
scale-50 opacity-0
|
||||||
|
group-hover:opacity-100
|
||||||
|
group-hover:scale-100
|
||||||
|
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
|
||||||
|
origin-center"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<Close class="z-10 pointer-events-none" size={14} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.titlebar {
|
.titlebar {
|
||||||
height: 35px;
|
height: 35px;
|
||||||
/* background: #040612; */
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 10px;
|
gap: 5px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -45,19 +63,4 @@
|
|||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
.titlebar-button {
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 25px;
|
|
||||||
height: 25px;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
|
||||||
.titlebar-button:hover {
|
|
||||||
&.close {
|
|
||||||
background: #c22e2e;
|
|
||||||
}
|
|
||||||
background: #2d3049;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export const currentLoadingInfo = writable<string>('Initializing...');
|
|||||||
export const firstStartup = writable<boolean>(false);
|
export const firstStartup = writable<boolean>(false);
|
||||||
|
|
||||||
export const launching = writable<boolean>(false);
|
export const launching = writable<boolean>(false);
|
||||||
|
export const nyanCatSong = writable<HTMLAudioElement | undefined>(undefined);
|
||||||
|
|
||||||
export const serverPing = writable<number | undefined>(undefined);
|
export const serverPing = writable<number | undefined>(undefined);
|
||||||
export const serverConnectionFails = writable(0);
|
export const serverConnectionFails = writable(0);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Logo from '$assets/logo.png';
|
import Logo from '$assets/logo.png';
|
||||||
|
import NyanCatSong from '$assets/nyan-cat.mp3';
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
|
|
||||||
import Titlebar from '@/components/ui/titlebar/titlebar.svelte';
|
import Titlebar from '@/components/ui/titlebar/titlebar.svelte';
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
discordPresence,
|
discordPresence,
|
||||||
firstStartup,
|
firstStartup,
|
||||||
launcherVersion,
|
launcherVersion,
|
||||||
|
nyanCatSong,
|
||||||
platform,
|
platform,
|
||||||
presenceLoading,
|
presenceLoading,
|
||||||
setupValues,
|
setupValues,
|
||||||
@@ -30,14 +32,18 @@
|
|||||||
import { encryptString, exit, getLauncherVersion, getPlatform } from '@/osuUtil';
|
import { encryptString, exit, getLauncherVersion, getPlatform } from '@/osuUtil';
|
||||||
import Button from '@/components/ui/button/button.svelte';
|
import Button from '@/components/ui/button/button.svelte';
|
||||||
import * as presence from '@/presence';
|
import * as presence from '@/presence';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
import '@fontsource/sora';
|
import '@fontsource/sora';
|
||||||
import '@fontsource/space-mono';
|
import '@fontsource/space-mono';
|
||||||
import AnimatedBg from '@/components/ui/animated-bg/AnimatedBg.svelte';
|
import AnimatedBg from '@/components/ui/animated-bg/AnimatedBg.svelte';
|
||||||
|
import NyanCatBg from '@/components/ui/animated-bg/NyanCatBg.svelte';
|
||||||
|
import { sileo } from 'sileo';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
let unsupported_platform = $state<boolean>(false);
|
let unsupported_platform = $state<boolean>(false);
|
||||||
|
let secret_enabled = $state<boolean>(false);
|
||||||
|
|
||||||
function disableReload() {
|
function disableReload() {
|
||||||
if (window.location.hostname !== 'tauri.localhost') {
|
if (window.location.hostname !== 'tauri.localhost') {
|
||||||
@@ -87,6 +93,19 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let konami_code = [
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'b',
|
||||||
|
'a',
|
||||||
|
];
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
window.Buffer = Buffer;
|
window.Buffer = Buffer;
|
||||||
|
|
||||||
@@ -98,6 +117,107 @@
|
|||||||
const isFirstStartup = await $userSettings.init();
|
const isFirstStartup = await $userSettings.init();
|
||||||
$userAuth.init();
|
$userAuth.init();
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key.toLowerCase() === konami_code[0].toLowerCase()) {
|
||||||
|
konami_code.shift();
|
||||||
|
if (konami_code.length === 0) {
|
||||||
|
if (secret_enabled) {
|
||||||
|
sileo.success({
|
||||||
|
title: 'Cheatcode deactivated!',
|
||||||
|
duration: 3000,
|
||||||
|
fill: '#181825',
|
||||||
|
styles: {
|
||||||
|
description: 'text-center!',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const audio = $nyanCatSong;
|
||||||
|
if (audio) {
|
||||||
|
const fadeOutDuration = 2000; // 2 seconds
|
||||||
|
const fadeOutSteps = 20;
|
||||||
|
const fadeOutStepTime = fadeOutDuration / fadeOutSteps;
|
||||||
|
const volumeStep = audio.volume / fadeOutSteps;
|
||||||
|
|
||||||
|
const fadeOutInterval = setInterval(() => {
|
||||||
|
if (audio.volume > 0) {
|
||||||
|
audio.volume = Math.max(0, audio.volume - volumeStep);
|
||||||
|
} else {
|
||||||
|
audio.pause();
|
||||||
|
clearInterval(fadeOutInterval);
|
||||||
|
}
|
||||||
|
}, fadeOutStepTime);
|
||||||
|
}
|
||||||
|
nyanCatSong.set(undefined);
|
||||||
|
secret_enabled = false;
|
||||||
|
konami_code = [
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'b',
|
||||||
|
'a',
|
||||||
|
];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sileo.success({
|
||||||
|
title: 'Cheatcode activated!',
|
||||||
|
duration: 3000,
|
||||||
|
fill: '#181825',
|
||||||
|
styles: {
|
||||||
|
description: 'text-center!',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const audio = new Audio(NyanCatSong);
|
||||||
|
audio.loop = true;
|
||||||
|
audio.volume = 0;
|
||||||
|
audio.play();
|
||||||
|
const fadeInDuration = 2000; // 2 seconds
|
||||||
|
const fadeInSteps = 20;
|
||||||
|
const fadeInStepTime = fadeInDuration / fadeInSteps;
|
||||||
|
const volumeStep = (1 - audio.volume) / fadeInSteps;
|
||||||
|
|
||||||
|
const fadeInInterval = setInterval(() => {
|
||||||
|
if (audio.volume < 0.3) {
|
||||||
|
audio.volume = Math.min(0.3, audio.volume + volumeStep);
|
||||||
|
} else {
|
||||||
|
clearInterval(fadeInInterval);
|
||||||
|
}
|
||||||
|
}, fadeInStepTime);
|
||||||
|
nyanCatSong.set(audio);
|
||||||
|
|
||||||
|
secret_enabled = true;
|
||||||
|
konami_code = [
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'b',
|
||||||
|
'a',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
konami_code = [
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowUp',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowDown',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'ArrowLeft',
|
||||||
|
'ArrowRight',
|
||||||
|
'b',
|
||||||
|
'a',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
currentLoadingInfo.set('Loading config...');
|
currentLoadingInfo.set('Loading config...');
|
||||||
const config_patching = $userSettings.value('patching');
|
const config_patching = $userSettings.value('patching');
|
||||||
const config_custom_cursor = $userSettings.value('custom_cursor');
|
const config_custom_cursor = $userSettings.value('custom_cursor');
|
||||||
@@ -180,7 +300,15 @@
|
|||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div class="opacity-30">
|
<div class="opacity-30">
|
||||||
|
{#if secret_enabled}
|
||||||
|
<div transition:fade={{ duration: $reduceAnimations ? 0 : 500 }}>
|
||||||
|
<NyanCatBg />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div transition:fade={{ duration: $reduceAnimations ? 0 : 500 }}>
|
||||||
<AnimatedBg />
|
<AnimatedBg />
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
launcherVersion,
|
launcherVersion,
|
||||||
launching,
|
launching,
|
||||||
newVersion,
|
newVersion,
|
||||||
|
nyanCatSong,
|
||||||
osuBuild,
|
osuBuild,
|
||||||
osuStream,
|
osuStream,
|
||||||
platform,
|
platform,
|
||||||
@@ -426,6 +427,25 @@
|
|||||||
}
|
}
|
||||||
await new Promise((res) => setTimeout(res, 1500));
|
await new Promise((res) => setTimeout(res, 1500));
|
||||||
launchInfo = 'Launching osu!...';
|
launchInfo = 'Launching osu!...';
|
||||||
|
|
||||||
|
if ($nyanCatSong) {
|
||||||
|
const audio = $nyanCatSong;
|
||||||
|
const fadeOutDuration = 2000; // 2 seconds
|
||||||
|
const fadeOutSteps = 20;
|
||||||
|
const fadeOutStepTime = fadeOutDuration / fadeOutSteps;
|
||||||
|
const volumeStep = audio.volume / fadeOutSteps;
|
||||||
|
|
||||||
|
const fadeOutInterval = setInterval(() => {
|
||||||
|
if (audio.volume > 0) {
|
||||||
|
audio.volume = Math.max(0, audio.volume - volumeStep);
|
||||||
|
} else {
|
||||||
|
clearInterval(fadeOutInterval);
|
||||||
|
audio.pause();
|
||||||
|
audio.currentTime = 0;
|
||||||
|
}
|
||||||
|
}, fadeOutStepTime);
|
||||||
|
}
|
||||||
|
|
||||||
await replaceUIFiles(osuPath, false);
|
await replaceUIFiles(osuPath, false);
|
||||||
await new Promise((res) => setTimeout(res, 1000));
|
await new Promise((res) => setTimeout(res, 1000));
|
||||||
await getCurrentWindow().hide();
|
await getCurrentWindow().hide();
|
||||||
@@ -535,6 +555,26 @@
|
|||||||
if ($trackingEnabled) umami.track('app_exit_osu');
|
if ($trackingEnabled) umami.track('app_exit_osu');
|
||||||
cleanup = true;
|
cleanup = true;
|
||||||
launchInfo = 'Cleaning up...';
|
launchInfo = 'Cleaning up...';
|
||||||
|
|
||||||
|
if ($nyanCatSong) {
|
||||||
|
const audio = $nyanCatSong;
|
||||||
|
audio.play();
|
||||||
|
audio.volume = 0;
|
||||||
|
|
||||||
|
const fadeInDuration = 2000; // 2 seconds
|
||||||
|
const fadeInSteps = 20;
|
||||||
|
const fadeInStepTime = fadeInDuration / fadeInSteps;
|
||||||
|
const volumeStep = (1 - audio.volume) / fadeInSteps;
|
||||||
|
|
||||||
|
const fadeInInterval = setInterval(() => {
|
||||||
|
if (audio.volume < 0.3) {
|
||||||
|
audio.volume = Math.min(0.3, audio.volume + volumeStep);
|
||||||
|
} else {
|
||||||
|
clearInterval(fadeInInterval);
|
||||||
|
}
|
||||||
|
}, fadeInStepTime);
|
||||||
|
}
|
||||||
|
|
||||||
await getCurrentWindow().show();
|
await getCurrentWindow().show();
|
||||||
if (presenceUpdater) {
|
if (presenceUpdater) {
|
||||||
window.clearInterval(presenceUpdater);
|
window.clearInterval(presenceUpdater);
|
||||||
@@ -948,8 +988,13 @@
|
|||||||
{#if selectedView === 'home'}
|
{#if selectedView === 'home'}
|
||||||
<div
|
<div
|
||||||
class="flex flex-col-reverse h-full"
|
class="flex flex-col-reverse h-full"
|
||||||
in:fly={{ duration: 400, delay: 400, y: 5, opacity: 0 }}
|
in:fly={{
|
||||||
out:fly={{ duration: 400, y: -5, opacity: 0 }}
|
duration: $reduceAnimations ? 0 : 400,
|
||||||
|
delay: $reduceAnimations ? 0 : 400,
|
||||||
|
y: 5,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
out:fly={{ duration: $reduceAnimations ? 0 : 400, y: -5, opacity: 0 }}
|
||||||
>
|
>
|
||||||
<div class="relative z-10 px-8 py-4 flex items-center justify-between">
|
<div class="relative z-10 px-8 py-4 flex items-center justify-between">
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
@@ -1070,8 +1115,8 @@
|
|||||||
{#if $currentUserInfo}
|
{#if $currentUserInfo}
|
||||||
<div
|
<div
|
||||||
class="m-1 w-72 h-48 bg-black/40 backdrop-blur-sm rounded-md border border-black/40 flex flex-col items-center p-3"
|
class="m-1 w-72 h-48 bg-black/40 backdrop-blur-sm rounded-md border border-black/40 flex flex-col items-center p-3"
|
||||||
in:fly={{ duration: 400, y: 5, opacity: 0 }}
|
in:fly={{ duration: $reduceAnimations ? 0 : 400, y: 5, opacity: 0 }}
|
||||||
out:fly={{ duration: 400, y: -5, opacity: 0 }}
|
out:fly={{ duration: $reduceAnimations ? 0 : 400, y: -5, opacity: 0 }}
|
||||||
>
|
>
|
||||||
<Select.Root
|
<Select.Root
|
||||||
type="single"
|
type="single"
|
||||||
@@ -1223,8 +1268,13 @@
|
|||||||
{:else if selectedView === 'settings'}
|
{:else if selectedView === 'settings'}
|
||||||
<div
|
<div
|
||||||
class="h-[100vh] w-full flex flex-col items-center justify-center"
|
class="h-[100vh] w-full flex flex-col items-center justify-center"
|
||||||
in:fly={{ duration: 400, delay: 400, y: 5, opacity: 0 }}
|
in:fly={{
|
||||||
out:fly={{ duration: 400, y: -5, opacity: 0 }}
|
duration: $reduceAnimations ? 0 : 400,
|
||||||
|
delay: $reduceAnimations ? 0 : 400,
|
||||||
|
y: 5,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
out:fly={{ duration: $reduceAnimations ? 0 : 400, y: -5, opacity: 0 }}
|
||||||
>
|
>
|
||||||
<div class="p-8 w-full">
|
<div class="p-8 w-full">
|
||||||
<div class="bg-black/40 backdrop-blur-sm py-8 px-6 rounded-lg">
|
<div class="bg-black/40 backdrop-blur-sm py-8 px-6 rounded-lg">
|
||||||
@@ -1425,8 +1475,13 @@
|
|||||||
{:else if selectedView === 'login'}
|
{:else if selectedView === 'login'}
|
||||||
<div
|
<div
|
||||||
class="h-[100vh] w-full flex flex-col items-center justify-center"
|
class="h-[100vh] w-full flex flex-col items-center justify-center"
|
||||||
in:fly={{ duration: 400, delay: 400, y: 5, opacity: 0 }}
|
in:fly={{
|
||||||
out:fly={{ duration: 400, y: -5, opacity: 0 }}
|
duration: $reduceAnimations ? 0 : 400,
|
||||||
|
delay: $reduceAnimations ? 0 : 400,
|
||||||
|
y: 5,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
out:fly={{ duration: $reduceAnimations ? 0 : 400, y: -5, opacity: 0 }}
|
||||||
>
|
>
|
||||||
<div class="p-8 px-52 w-full">
|
<div class="p-8 px-52 w-full">
|
||||||
<form onsubmit={performLogin} class="bg-black/40 backdrop-blur-sm rounded-lg p-8">
|
<form onsubmit={performLogin} class="bg-black/40 backdrop-blur-sm rounded-lg p-8">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import { animate } from 'animejs';
|
import { animate } from 'animejs';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import { Check, CheckCircle, CircleOff, Settings2 } from 'lucide-svelte';
|
import { Check, CircleCheckBig, CircleOff, LoaderCircle } from 'lucide-svelte';
|
||||||
import { open } from '@tauri-apps/plugin-dialog';
|
import { open } from '@tauri-apps/plugin-dialog';
|
||||||
import Checkbox from '@/components/ui/checkbox/checkbox.svelte';
|
import Checkbox from '@/components/ui/checkbox/checkbox.svelte';
|
||||||
import {
|
import {
|
||||||
@@ -17,7 +17,17 @@
|
|||||||
userSettings,
|
userSettings,
|
||||||
} from '@/userSettings';
|
} from '@/userSettings';
|
||||||
import Label from '@/components/ui/label/label.svelte';
|
import Label from '@/components/ui/label/label.svelte';
|
||||||
import { beatmapSets, currentSkin, currentView, osuBuild, osuStream, skins } from '@/global';
|
import {
|
||||||
|
beatmapSets,
|
||||||
|
currentSkin,
|
||||||
|
currentView,
|
||||||
|
discordPresence,
|
||||||
|
osuBuild,
|
||||||
|
osuStream,
|
||||||
|
platform,
|
||||||
|
presenceLoading,
|
||||||
|
skins,
|
||||||
|
} from '@/global';
|
||||||
import Launch from './Launch.svelte';
|
import Launch from './Launch.svelte';
|
||||||
import Confetti from 'svelte-confetti';
|
import Confetti from 'svelte-confetti';
|
||||||
import {
|
import {
|
||||||
@@ -130,14 +140,16 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="grid grid-cols-[0.41fr_1fr] h-[100vh] z-50">
|
<div class="grid grid-cols-[0.41fr_1fr] h-[100vh] z-50">
|
||||||
<div class="w-full h-full border-r border-theme-800 bg-black/20 backdrop-blur-md flex flex-col gap-6 p-3 z-50">
|
<div
|
||||||
|
class="w-full h-full border-r border-black/40 bg-black/40 backdrop-blur-md flex flex-col gap-6 p-3 z-50"
|
||||||
|
>
|
||||||
{#each steps as step, i (step)}
|
{#each steps as step, i (step)}
|
||||||
<div
|
<div
|
||||||
class="flex flex-row items-center gap-2 border {selectedStep === i + 1
|
class="flex flex-row items-center gap-2 border {selectedStep === i + 1
|
||||||
? 'border-primary-800 bg-primary-900'
|
? 'border-primary-600/30 bg-primary-700/30'
|
||||||
: selectedStep > i
|
: selectedStep > i
|
||||||
? 'border-green-800 bg-green-900'
|
? 'border-green-800/30 bg-green-900/30'
|
||||||
: 'border-theme-800 bg-theme-900'} rounded-lg p-2 transition-all"
|
: 'border-black/30 bg-black/30'} rounded-lg p-2 transition-all"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center justify-center h-8 w-8 border-[2px] {selectedStep >
|
class="flex flex-col items-center justify-center h-8 w-8 border-[2px] {selectedStep >
|
||||||
@@ -164,7 +176,7 @@
|
|||||||
<div class="flex flex-col gap-6 w-full h-full backdrop-blur-md p-6 z-50">
|
<div class="flex flex-col gap-6 w-full h-full backdrop-blur-md p-6 z-50">
|
||||||
{#if selectedStep === 1}
|
{#if selectedStep === 1}
|
||||||
<div
|
<div
|
||||||
class="my-auto h-full w-full bg-black/20 rounded-lg border border-theme-900/20 p-6 mt-5 flex flex-col items-center justify-center"
|
class="my-auto h-full w-full bg-black/40 rounded-lg border border-black/40 p-6 mt-5 flex flex-col items-center justify-center"
|
||||||
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
|
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -179,13 +191,13 @@
|
|||||||
<p class="text-muted-foreground mt-2">
|
<p class="text-muted-foreground mt-2">
|
||||||
This setup wizard will guide you through the initial setup of EZPPLauncher.
|
This setup wizard will guide you through the initial setup of EZPPLauncher.
|
||||||
</p>
|
</p>
|
||||||
<div class="bg-red-800 border border-red-900 text-red-500 p-4 rounded-lg mt-4">
|
<div class="bg-red-800 border border-red-900 text-red-200 p-4 rounded-lg mt-4">
|
||||||
Please make sure you have osu! installed on your system before proceeding.
|
Please make sure you have osu! installed on your system before proceeding.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else if selectedStep === 2}
|
{:else if selectedStep === 2}
|
||||||
<div
|
<div
|
||||||
class="my-auto h-full w-full bg-theme-800 rounded-lg border border-theme-900 p-6 mt-5 flex flex-col items-center justify-center"
|
class="my-auto h-full w-full bg-black/40 rounded-lg border border-black/40 p-6 mt-5 flex flex-col items-center justify-center"
|
||||||
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
|
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
|
||||||
>
|
>
|
||||||
<h1 class="text-3xl font-semibold">Locate your osu! Installation</h1>
|
<h1 class="text-3xl font-semibold">Locate your osu! Installation</h1>
|
||||||
@@ -210,7 +222,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-row gap-3 bg-green-800 border border-green-900 text-green-500 p-4 rounded-lg mt-4"
|
class="flex flex-row gap-3 bg-green-800 border border-green-900 text-green-500 p-4 rounded-lg mt-4"
|
||||||
>
|
>
|
||||||
<CheckCircle />
|
<CircleCheckBig />
|
||||||
<span>Auto-detected osu! installation path! Please check if its correct!</span>
|
<span>Auto-detected osu! installation path! Please check if its correct!</span>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -226,7 +238,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-row gap-3 bg-green-800 border border-green-900 text-green-500 p-4 rounded-lg mt-4"
|
class="flex flex-row gap-3 bg-green-800 border border-green-900 text-green-500 p-4 rounded-lg mt-4"
|
||||||
>
|
>
|
||||||
<CheckCircle />
|
<CircleCheckBig />
|
||||||
<span>Selected osu! installation path is valid!</span>
|
<span>Selected osu! installation path is valid!</span>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -242,23 +254,26 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else if selectedStep === 3}
|
{:else if selectedStep === 3}
|
||||||
|
<div class="h-full w-full flex items-center justify-center">
|
||||||
<div
|
<div
|
||||||
class="bg-theme-900 flex flex-col justify-center gap-3 mt-5 border border-theme-800 rounded-lg"
|
class="bg-black/40 backdrop-blur-sm py-8 px-8 rounded-lg"
|
||||||
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
|
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
|
||||||
>
|
>
|
||||||
<div class="flex flex-row items-center gap-3 font-semibold text-xl px-3 pt-3">
|
<div class="grid grid-cols-[1fr_auto] gap-y-5 items-center px-6">
|
||||||
<Settings2 /> EZPPLauncher Settings
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="grid grid-cols-[1fr_auto] gap-y-5 items-center border-t border-theme-800 py-3 px-6"
|
|
||||||
>
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<Label class="text-sm" for="setting-custom-cursor">Patching</Label>
|
<Label class="text-sm" for="setting-patch">Patching</Label>
|
||||||
<div class="text-muted-foreground text-xs">Shows misses in Relax and Autopilot</div>
|
<div class="text-muted-foreground text-xs">
|
||||||
|
Shows misses in Relax and Autopilot {#if $platform !== 'windows'}<span
|
||||||
|
class="text-red-500 bg-red-800/20 border border-red-600/20 p-0.5 mx-1 px-2 rounded-lg !text-[0.55rem]"
|
||||||
|
>currently only on windows!</span
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="setting-custom-cursor"
|
id="setting-patch"
|
||||||
checked={$patch}
|
checked={$platform === 'windows' ? $patch : false}
|
||||||
|
disabled={$platform !== 'windows'}
|
||||||
onCheckedChange={async (e) => {
|
onCheckedChange={async (e) => {
|
||||||
patch.set(e);
|
patch.set(e);
|
||||||
$userSettings.save();
|
$userSettings.save();
|
||||||
@@ -280,6 +295,8 @@
|
|||||||
cursorSmoothening.set(false);
|
cursorSmoothening.set(false);
|
||||||
}
|
}
|
||||||
customCursor.set(e);
|
customCursor.set(e);
|
||||||
|
|
||||||
|
$userSettings.save();
|
||||||
}}
|
}}
|
||||||
class="flex items-center justify-center w-5 h-5"
|
class="flex items-center justify-center w-5 h-5"
|
||||||
></Checkbox>
|
></Checkbox>
|
||||||
@@ -296,26 +313,49 @@
|
|||||||
onCheckedChange={async (e) => {
|
onCheckedChange={async (e) => {
|
||||||
if (!$customCursor) return;
|
if (!$customCursor) return;
|
||||||
cursorSmoothening.set(e);
|
cursorSmoothening.set(e);
|
||||||
|
$userSettings.save();
|
||||||
}}
|
}}
|
||||||
disabled={!$customCursor}
|
disabled={!$customCursor}
|
||||||
class="flex items-center justify-center w-5 h-5"
|
class="flex items-center justify-center w-5 h-5"
|
||||||
></Checkbox>
|
></Checkbox>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<Label class="text-sm" for="setting-cursor-smoothening">Reduce Animations</Label>
|
<Label class="text-sm" for="setting-reduce-animations">Reduce Animations</Label>
|
||||||
<div class="text-muted-foreground text-xs">
|
<div class="text-muted-foreground text-xs">
|
||||||
Disables some animations in the Launcher to improve performance on low-end devices.
|
Disables some animations in the Launcher to improve performance on low-end
|
||||||
|
devices.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="setting-cursor-smoothening"
|
id="setting-reduce-animations"
|
||||||
checked={$reduceAnimations}
|
checked={$reduceAnimations}
|
||||||
onCheckedChange={async (e) => {
|
onCheckedChange={async (e) => {
|
||||||
reduceAnimations.set(e);
|
reduceAnimations.set(e);
|
||||||
|
$userSettings.save();
|
||||||
}}
|
}}
|
||||||
disabled={!$customCursor}
|
|
||||||
class="flex items-center justify-center w-5 h-5"
|
class="flex items-center justify-center w-5 h-5"
|
||||||
></Checkbox>
|
></Checkbox>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Label class="text-sm" for="setting-rich-presence">Discord Rich Presence</Label>
|
||||||
|
<div class="text-muted-foreground text-xs">
|
||||||
|
Let other discord users show what you are doing right now 👀
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="relative">
|
||||||
|
{#if $presenceLoading}
|
||||||
|
<div class="-left-8 absolute" transition:fade>
|
||||||
|
<LoaderCircle class="animate-spin" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<Checkbox
|
||||||
|
id="setting-rich-presence"
|
||||||
|
bind:checked={$discordPresence}
|
||||||
|
disabled={$presenceLoading}
|
||||||
|
class="flex items-center justify-center w-5 h-5"
|
||||||
|
></Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user