Compare commits
3 Commits
9770e81d6f
...
24802b5132
| Author | SHA1 | Date | |
|---|---|---|---|
| 24802b5132 | |||
| f09405ed58 | |||
| eeda85f48f |
Generated
+44
@@ -475,8 +475,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -995,6 +997,7 @@ dependencies = [
|
|||||||
"md5",
|
"md5",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"open",
|
"open",
|
||||||
|
"osynic_osudb",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -2052,6 +2055,26 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "liblzma"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6033b77c21d1f56deeae8014eb9fbe7bdf1765185a6c508b5ca82eeaed7f899"
|
||||||
|
dependencies = [
|
||||||
|
"liblzma-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "liblzma-sys"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f2db66f3268487b5033077f266da6777d057949b8f93c8ad82e441df25e6186"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@@ -2262,6 +2285,15 @@ version = "0.1.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "8.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ntapi"
|
name = "ntapi"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -2605,6 +2637,18 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "osynic_osudb"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d7f03567d97cdc0bf54380f0c525a00de1ce58ed9497f2409dfaf6112346b8a"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"liblzma",
|
||||||
|
"nom",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango"
|
name = "pango"
|
||||||
version = "0.18.3"
|
version = "0.18.3"
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ open = "5.3.3"
|
|||||||
discord-rich-presence = "1.1.0"
|
discord-rich-presence = "1.1.0"
|
||||||
once_cell = "1.21.3"
|
once_cell = "1.21.3"
|
||||||
futures-util = "0.3.32"
|
futures-util = "0.3.32"
|
||||||
|
osynic_osudb = "0.1.4"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winreg = "0.55.0"
|
winreg = "0.55.0"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use hardware_id::get_id;
|
use hardware_id::get_id;
|
||||||
|
use osynic_osudb::entity::osu::osudb::OsuDB;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@@ -156,33 +157,14 @@ pub fn find_osu_installation() -> Option<String> {
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_beatmapsets_count(folder: String) -> Option<u64> {
|
pub async fn get_beatmapsets_count(folder: String) -> Option<u64> {
|
||||||
let path = PathBuf::from(folder);
|
let path = PathBuf::from(folder);
|
||||||
let osu_user_config = get_osu_user_config(path.clone());
|
let osu_db_path = path.join("osu!.db");
|
||||||
let songs_path = osu_user_config
|
if !osu_db_path.exists() {
|
||||||
.and_then(|config| config.get("Songs").cloned())
|
return Some(0);
|
||||||
.unwrap_or_else(|| path.join("Songs").to_string_lossy().into_owned());
|
|
||||||
let songs_folder = PathBuf::from(songs_path);
|
|
||||||
|
|
||||||
if !songs_folder.exists() {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
let mut osudb = OsuDB::from_file(&osu_db_path).unwrap();
|
||||||
let mut count = 0;
|
let beatmaps = osudb.beatmaps.iter_mut();
|
||||||
if let Ok(mut entries) = fs::read_dir(songs_folder).await {
|
let beatmap_sets = beatmaps.map(|b| b.beatmapset_id).collect::<HashSet<_>>();
|
||||||
while let Ok(Some(entry)) = entries.next_entry().await {
|
return Some(beatmap_sets.len() as u64);
|
||||||
if entry.file_type().await.map_or(false, |ft| ft.is_dir()) {
|
|
||||||
let dir_path = entry.path();
|
|
||||||
if let Ok(mut files) = fs::read_dir(&dir_path).await {
|
|
||||||
while let Ok(Some(file)) = files.next_entry().await {
|
|
||||||
if file.path().extension().map_or(false, |ext| ext == "osu") {
|
|
||||||
count += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Some(count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<div class="relative flex items-center justify-center p-1 group" id="titlebar-minimize">
|
<div class="relative flex items-center justify-center p-1 group" id="titlebar-minimize">
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 bg-background rounded
|
class="absolute inset-0 bg-background rounded
|
||||||
scale-50 opacity-0
|
scale-80 opacity-0
|
||||||
group-hover:opacity-100
|
group-hover:opacity-100
|
||||||
group-hover:scale-100
|
group-hover:scale-100
|
||||||
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
|
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
<div class="relative flex items-center justify-center p-1 group" id="titlebar-close">
|
<div class="relative flex items-center justify-center p-1 group" id="titlebar-close">
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 bg-red-500 rounded
|
class="absolute inset-0 bg-red-500 rounded
|
||||||
scale-50 opacity-0
|
scale-80 opacity-0
|
||||||
group-hover:opacity-100
|
group-hover:opacity-100
|
||||||
group-hover:scale-100
|
group-hover:scale-100
|
||||||
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
|
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
|
||||||
|
|||||||
@@ -174,14 +174,15 @@
|
|||||||
audio.loop = true;
|
audio.loop = true;
|
||||||
audio.volume = 0;
|
audio.volume = 0;
|
||||||
audio.play();
|
audio.play();
|
||||||
|
const fadeInVolume = 0.15;
|
||||||
const fadeInDuration = 2000; // 2 seconds
|
const fadeInDuration = 2000; // 2 seconds
|
||||||
const fadeInSteps = 20;
|
const fadeInSteps = 20;
|
||||||
const fadeInStepTime = fadeInDuration / fadeInSteps;
|
const fadeInStepTime = fadeInDuration / fadeInSteps;
|
||||||
const volumeStep = (1 - audio.volume) / fadeInSteps;
|
const volumeStep = (fadeInVolume - audio.volume) / fadeInSteps;
|
||||||
|
|
||||||
const fadeInInterval = setInterval(() => {
|
const fadeInInterval = setInterval(() => {
|
||||||
if (audio.volume < 0.3) {
|
if (audio.volume < fadeInVolume) {
|
||||||
audio.volume = Math.min(0.3, audio.volume + volumeStep);
|
audio.volume = Math.min(fadeInVolume, audio.volume + volumeStep);
|
||||||
} else {
|
} else {
|
||||||
clearInterval(fadeInInterval);
|
clearInterval(fadeInInterval);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-112
@@ -112,9 +112,6 @@
|
|||||||
import DownloadButton from '@/components/ui/download-button/DownloadButton.svelte';
|
import DownloadButton from '@/components/ui/download-button/DownloadButton.svelte';
|
||||||
import { animate } from 'animejs';
|
import { animate } from 'animejs';
|
||||||
import { sileo } from 'sileo';
|
import { sileo } from 'sileo';
|
||||||
import Check from '@lucide/svelte/icons/check';
|
|
||||||
import ScrollContainer from '@/components/ui/scroll-container/ScrollContainer.svelte';
|
|
||||||
import { sortSkins } from '@/sort';
|
|
||||||
|
|
||||||
let selectedView = $state('home');
|
let selectedView = $state('home');
|
||||||
let progress = $state(-1);
|
let progress = $state(-1);
|
||||||
@@ -573,14 +570,15 @@
|
|||||||
audio.play();
|
audio.play();
|
||||||
audio.volume = 0;
|
audio.volume = 0;
|
||||||
|
|
||||||
|
const fadeInVolume = 0.15;
|
||||||
const fadeInDuration = 2000; // 2 seconds
|
const fadeInDuration = 2000; // 2 seconds
|
||||||
const fadeInSteps = 20;
|
const fadeInSteps = 20;
|
||||||
const fadeInStepTime = fadeInDuration / fadeInSteps;
|
const fadeInStepTime = fadeInDuration / fadeInSteps;
|
||||||
const volumeStep = (1 - audio.volume) / fadeInSteps;
|
const volumeStep = (fadeInVolume - audio.volume) / fadeInSteps;
|
||||||
|
|
||||||
const fadeInInterval = setInterval(() => {
|
const fadeInInterval = setInterval(() => {
|
||||||
if (audio.volume < 0.3) {
|
if (audio.volume < fadeInVolume) {
|
||||||
audio.volume = Math.min(0.3, audio.volume + volumeStep);
|
audio.volume = Math.min(fadeInVolume, audio.volume + volumeStep);
|
||||||
} else {
|
} else {
|
||||||
clearInterval(fadeInInterval);
|
clearInterval(fadeInInterval);
|
||||||
}
|
}
|
||||||
@@ -945,18 +943,6 @@
|
|||||||
>
|
>
|
||||||
<House class="text-theme-200 !size-5" />
|
<House class="text-theme-200 !size-5" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
class="flex size-12 items-center gap-2 ring-1 ring-inset ring-white/15 {selectedView ===
|
|
||||||
'skins'
|
|
||||||
? 'bg-primary-300/50'
|
|
||||||
: 'bg-black/20 border-black/20'} hover:bg-primary-300/50 rounded-[0.85rem] p-3 mt-3"
|
|
||||||
disabled={$launching}
|
|
||||||
onclick={() => {
|
|
||||||
if (!$launching) selectedView = 'skins';
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paintbrush class="text-theme-200 !size-5" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
<Button
|
||||||
class="flex size-12 items-center gap-2 ring-1 ring-inset ring-white/15 {selectedView ===
|
class="flex size-12 items-center gap-2 ring-1 ring-inset ring-white/15 {selectedView ===
|
||||||
'settings'
|
'settings'
|
||||||
@@ -1545,100 +1531,6 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{:else if selectedView === 'skins'}
|
|
||||||
<div
|
|
||||||
class="h-[100vh] w-full flex flex-col items-center justify-center bg-black/20 backdrop-blur-sm"
|
|
||||||
in:fly={{
|
|
||||||
duration: $reduceAnimations ? 0 : 400,
|
|
||||||
delay: $reduceAnimations ? 0 : 400,
|
|
||||||
y: 5,
|
|
||||||
opacity: 0,
|
|
||||||
}}
|
|
||||||
out:fly={{ duration: $reduceAnimations ? 0 : 400, y: -5, opacity: 0 }}
|
|
||||||
>
|
|
||||||
{#if $skins.length > 0}
|
|
||||||
{@const skinsSorted = sortSkins($skins)}
|
|
||||||
<ScrollContainer
|
|
||||||
class="flex flex-col max-h-[100vh] overflow-y-auto items-center gap-4 p-16 w-full"
|
|
||||||
topOffset={35}
|
|
||||||
>
|
|
||||||
{#each skinsSorted as skin (skin.name)}
|
|
||||||
<div
|
|
||||||
class={`group w-full flex items-center border rounded-lg transition-all duration-150 ${
|
|
||||||
skin.name === $currentSkin
|
|
||||||
? 'bg-primary/20 border-primary/40'
|
|
||||||
: 'bg-black/40 border-black/60 hover:bg-black/70 hover:border-border'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div class="flex-1 min-w-0 px-5 py-3.5">
|
|
||||||
<p class="text-sm text-foreground/90 truncate font-medium line-clamp-1">
|
|
||||||
{skin.name}
|
|
||||||
</p>
|
|
||||||
<div class="flex items-center gap-4 mt-1">
|
|
||||||
<span class="text-[11px] text-muted-foreground">
|
|
||||||
{skin.author || 'Unknown'}
|
|
||||||
</span>
|
|
||||||
<span class="text-[11px] text-muted-foreground/50">
|
|
||||||
{new Date(skin.modified * 1000).toLocaleDateString(undefined, {
|
|
||||||
year: '2-digit',
|
|
||||||
month: 'short',
|
|
||||||
day: 'numeric',
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="flex items-center gap-1.5 pr-3 opacity-0 group-hover:opacity-100 transition-opacity duration-150"
|
|
||||||
>
|
|
||||||
{#if $currentSkin !== skin.name}
|
|
||||||
<button
|
|
||||||
transition:fade={{
|
|
||||||
duration: 150,
|
|
||||||
}}
|
|
||||||
class="p-2 rounded-md text-muted-foreground hover:text-primary hover:bg-primary/10 transition-colors"
|
|
||||||
onclick={async () => {
|
|
||||||
if (skin.name === $currentSkin) return;
|
|
||||||
await setUserConfigValues($osuInstallationPath, [
|
|
||||||
{ key: 'Skin', value: skin.name },
|
|
||||||
]);
|
|
||||||
currentSkin.set(skin.name);
|
|
||||||
sileo.success({
|
|
||||||
title: 'Skin applied!',
|
|
||||||
description: `${skin.name} is now your active skin!`,
|
|
||||||
fill: '#181825',
|
|
||||||
styles: {
|
|
||||||
description: 'text-center!',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Check class="w-4 h-4" />
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
<!-- <button
|
|
||||||
class="p-2 rounded-md transition-colors text-muted-foreground hover:text-destructive hover:bg-destructive/10"
|
|
||||||
>
|
|
||||||
<Trash2 class="w-4 h-4" />
|
|
||||||
</button> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</ScrollContainer>
|
|
||||||
{:else}
|
|
||||||
<div class="flex flex-col items-center justify-center gap-4">
|
|
||||||
<FileQuestionMark class="size-12 text-muted-foreground" strokeWidth={1.5} />
|
|
||||||
<span class="text-sm text-muted-foreground">No skins found!</span>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.custom-scrollbox {
|
|
||||||
scrollbar-color: #999 transparent;
|
|
||||||
scrollbar-width: 0px !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user