fix: volumeBar UI
This commit is contained in:
parent
7b87a649ac
commit
65a1c26f1e
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aquavox",
|
"name": "aquavox",
|
||||||
"version": "1.10.0",
|
"version": "1.10.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import formatDuration from '$lib/formatDuration';
|
import formatDuration from '$lib/formatDuration';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import userAdjustingProgress from '$lib/state/userAdjustingProgress';
|
import userAdjustingProgress from '$lib/state/userAdjustingProgress';
|
||||||
import progressBarRaw from '$lib/state/progressBarRaw';
|
import progressBarSlideValue from '$lib/state/progressBarSlideValue';
|
||||||
|
|
||||||
export let name: string;
|
export let name: string;
|
||||||
export let singer: string = '';
|
export let singer: string = '';
|
||||||
@ -18,22 +18,39 @@
|
|||||||
export let hasLyrics: boolean;
|
export let hasLyrics: boolean;
|
||||||
|
|
||||||
let progressBar: HTMLDivElement;
|
let progressBar: HTMLDivElement;
|
||||||
let volumeBar: HTMLInputElement;
|
let volumeBar: HTMLDivElement;
|
||||||
let showInfoTop: boolean = false;
|
let showInfoTop: boolean = false;
|
||||||
let isInfoTopOverflowing = false;
|
let isInfoTopOverflowing = false;
|
||||||
let songInfoTopContainer: HTMLDivElement;
|
let songInfoTopContainer: HTMLDivElement;
|
||||||
let songInfoTopContent: HTMLSpanElement;
|
let songInfoTopContent: HTMLSpanElement;
|
||||||
|
let lastTouchProgress: number;
|
||||||
|
let userAdjustingVolume = false;
|
||||||
|
|
||||||
const mql = window.matchMedia('(max-width: 1280px)');
|
const mql = window.matchMedia('(max-width: 1280px)');
|
||||||
|
|
||||||
function volumeBarOnChange(e: any) {
|
function volumeBarOnChange(e: MouseEvent) {
|
||||||
adjustVolume(e.target.value);
|
const value = e.offsetX / volumeBar.getBoundingClientRect().width;
|
||||||
localStorage.setItem('volume', e.target.value);
|
adjustVolume(value);
|
||||||
|
localStorage.setItem('volume', value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
function volumeBarChangeTouch(e: TouchEvent) {
|
||||||
|
const value = turncate(
|
||||||
|
e.touches[0].clientX - volumeBar.getBoundingClientRect().x,
|
||||||
|
0,
|
||||||
|
volumeBar.getBoundingClientRect().width
|
||||||
|
) / volumeBar.getBoundingClientRect().width;
|
||||||
|
adjustVolume(value);
|
||||||
|
localStorage.setItem('volume', value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
function progressBarOnClick(e: MouseEvent) {
|
function progressBarOnClick(e: MouseEvent) {
|
||||||
adjustProgress(e.offsetX / progressBar.getBoundingClientRect().width);
|
adjustProgress(e.offsetX / progressBar.getBoundingClientRect().width);
|
||||||
progressBarRaw.set(e.offsetX / progressBar.getBoundingClientRect().width * duration);
|
progressBarSlideValue.set((e.offsetX / progressBar.getBoundingClientRect().width) * duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
function turncate(value: number, min: number, max: number) {
|
||||||
|
return Math.min(Math.max(value, min), max);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -94,6 +111,30 @@
|
|||||||
adjustDisplayProgress(e.offsetX / progressBar.getBoundingClientRect().width);
|
adjustDisplayProgress(e.offsetX / progressBar.getBoundingClientRect().width);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
on:touchstart={(e) => {
|
||||||
|
if (e.cancelable) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
userAdjustingProgress.set(true);
|
||||||
|
}}
|
||||||
|
on:touchmove={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
userAdjustingProgress.set(true);
|
||||||
|
if ($userAdjustingProgress) {
|
||||||
|
lastTouchProgress =
|
||||||
|
turncate(
|
||||||
|
e.touches[0].clientX - progressBar.getBoundingClientRect().x,
|
||||||
|
0,
|
||||||
|
progressBar.getBoundingClientRect().width
|
||||||
|
) / progressBar.getBoundingClientRect().width;
|
||||||
|
adjustDisplayProgress(lastTouchProgress);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
on:touchend={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
userAdjustingProgress.set(false);
|
||||||
|
adjustProgress(lastTouchProgress);
|
||||||
|
}}
|
||||||
on:mouseup={() => {
|
on:mouseup={() => {
|
||||||
userAdjustingProgress.set(false);
|
userAdjustingProgress.set(false);
|
||||||
}}
|
}}
|
||||||
@ -127,7 +168,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="relative top-52 h-6 flex">
|
<div class="relative top-52 h-6 flex">
|
||||||
<img class="scale-75" src="/volumeDown.svg" alt="最小音量" />
|
<img class="scale-75" src="/volumeDown.svg" alt="最小音量" />
|
||||||
<input
|
<!-- <input
|
||||||
class="mx-2 progress-bar shadow-md !translate-y-[-50%] !top-1/2"
|
class="mx-2 progress-bar shadow-md !translate-y-[-50%] !top-1/2"
|
||||||
bind:this={volumeBar}
|
bind:this={volumeBar}
|
||||||
on:input={volumeBarOnChange}
|
on:input={volumeBarOnChange}
|
||||||
@ -136,7 +177,49 @@
|
|||||||
max="1"
|
max="1"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
value={$userAdjustingProgress ? volumeBar.value : volume}
|
value={$userAdjustingProgress ? volumeBar.value : volume}
|
||||||
/>
|
/> -->
|
||||||
|
<div
|
||||||
|
class="progress-bar shadow-md !top-1/2 !translate-y-[-50%]"
|
||||||
|
on:click={(e) => volumeBarOnChange(e)}
|
||||||
|
bind:this={volumeBar}
|
||||||
|
on:mousedown={() => {
|
||||||
|
userAdjustingVolume = true;
|
||||||
|
}}
|
||||||
|
on:mousemove={(e) => {
|
||||||
|
if (userAdjustingVolume) {
|
||||||
|
volumeBarOnChange(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
on:touchstart={(e) => {
|
||||||
|
if (e.cancelable) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
userAdjustingVolume = true;
|
||||||
|
}}
|
||||||
|
on:touchmove={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
userAdjustingVolume = true;
|
||||||
|
if (userAdjustingVolume) {
|
||||||
|
volumeBarChangeTouch(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
on:touchend={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
userAdjustingVolume = false;
|
||||||
|
}}
|
||||||
|
on:mouseup={() => {
|
||||||
|
userAdjustingVolume = false;
|
||||||
|
}}
|
||||||
|
role="slider"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="1"
|
||||||
|
aria-valuenow={volume}
|
||||||
|
tabindex="0"
|
||||||
|
on:keydown
|
||||||
|
on:keyup
|
||||||
|
>
|
||||||
|
<div class="bar" style={`width: ${volume * 100}%;`}></div>
|
||||||
|
</div>
|
||||||
<img class="scale-75" src="/volumeUp.svg" alt="最大音量" />
|
<img class="scale-75" src="/volumeUp.svg" alt="最大音量" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import createLyricsSearcher from '$lib/lyrics/lyricSearcher';
|
import createLyricsSearcher from '$lib/lyrics/lyricSearcher';
|
||||||
import progressBarRaw from '$lib/state/progressBarRaw';
|
import progressBarRaw from '$lib/state/progressBarRaw';
|
||||||
import type { LrcJsonData } from 'lrc-parser-ts';
|
import type { LrcJsonData } from 'lrc-parser-ts';
|
||||||
|
import progressBarSlideValue from '$lib/state/progressBarSlideValue';
|
||||||
export let lyrics: string[];
|
export let lyrics: string[];
|
||||||
export let originalLyrics: LrcJsonData;
|
export let originalLyrics: LrcJsonData;
|
||||||
export let progress: number;
|
export let progress: number;
|
||||||
@ -15,6 +16,7 @@
|
|||||||
let lyricsContainer: HTMLDivElement;
|
let lyricsContainer: HTMLDivElement;
|
||||||
let nextUpdate = -1;
|
let nextUpdate = -1;
|
||||||
let lastAdjustProgress = 0;
|
let lastAdjustProgress = 0;
|
||||||
|
let localProgress = 0;
|
||||||
|
|
||||||
let refs: HTMLParagraphElement[] = [];
|
let refs: HTMLParagraphElement[] = [];
|
||||||
let _refs: any[] = [];
|
let _refs: any[] = [];
|
||||||
@ -94,7 +96,6 @@
|
|||||||
const scripts = originalLyrics.scripts;
|
const scripts = originalLyrics.scripts;
|
||||||
if (!scripts) return;
|
if (!scripts) return;
|
||||||
if (v) {
|
if (v) {
|
||||||
console.log('!');
|
|
||||||
for (let i = 0; i < scripts.length; i++) {
|
for (let i = 0; i < scripts.length; i++) {
|
||||||
refs[i].style.filter = `blur(0px)`;
|
refs[i].style.filter = `blur(0px)`;
|
||||||
}
|
}
|
||||||
@ -109,10 +110,20 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// progressBarRaw is used to detect progress changes at system-level (not in AquaVox)
|
||||||
progressBarRaw.subscribe((progress: number) => {
|
progressBarRaw.subscribe((progress: number) => {
|
||||||
if ($userAdjustingProgress === false && getLyricIndex) {
|
if ($userAdjustingProgress === false && getLyricIndex) {
|
||||||
|
if (Math.abs(localProgress - progress) > 0.6) {
|
||||||
const currentLyric = refs[getLyricIndex(progress)];
|
const currentLyric = refs[getLyricIndex(progress)];
|
||||||
b(currentLyric);
|
b(currentLyric);
|
||||||
|
}
|
||||||
|
localProgress = progress;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// progressBarSlideValue is to detect progress bar sliding event
|
||||||
|
progressBarSlideValue.subscribe((_) => {
|
||||||
|
if ($userAdjustingProgress === false && getLyricIndex) {
|
||||||
lastAdjustProgress = currentPositionIndex;
|
lastAdjustProgress = currentPositionIndex;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -121,7 +132,7 @@
|
|||||||
if ($userAdjustingProgress) {
|
if ($userAdjustingProgress) {
|
||||||
nextUpdate = progress;
|
nextUpdate = progress;
|
||||||
} else {
|
} else {
|
||||||
if (0 < nextUpdate - progress && nextUpdate - progress < 0.05) {
|
if (nextUpdate - progress < 0.05) {
|
||||||
if (
|
if (
|
||||||
currentPositionIndex >= 0 &&
|
currentPositionIndex >= 0 &&
|
||||||
currentPositionIndex !== currentAnimationIndex &&
|
currentPositionIndex !== currentAnimationIndex &&
|
||||||
@ -163,9 +174,11 @@
|
|||||||
bind:this={lyricsContainer}
|
bind:this={lyricsContainer}
|
||||||
>
|
>
|
||||||
{#if debugMode}
|
{#if debugMode}
|
||||||
<p class="fixed top-6 right-20">
|
<p class="fixed top-6 right-20 font-mono text-sm">
|
||||||
LyricIndex: {currentLyricIndex} PositionIndex: {currentPositionIndex} AnimationIndex:{currentAnimationIndex}
|
LyricIndex: {currentLyricIndex} PositionIndex: {currentPositionIndex} AnimationIndex:{currentAnimationIndex}
|
||||||
NextUpdate: {Math.floor(nextUpdate / 60)}m {Math.round((nextUpdate % 60) * 100) / 100}s
|
NextUpdate: {nextUpdate}
|
||||||
|
Progress: {progress.toFixed(2)}
|
||||||
|
lastAdjustProgress: {lastAdjustProgress}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
{#each lyrics as lyric, i}
|
{#each lyrics as lyric, i}
|
||||||
|
3
src/lib/state/progressBarSlideValue.ts
Normal file
3
src/lib/state/progressBarSlideValue.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
const progressBarSlideValue = writable(0);
|
||||||
|
export default progressBarSlideValue;
|
@ -77,7 +77,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
AquaVox 1.10.0 · 早期公开预览 · 源代码参见
|
AquaVox 1.10.1 · 早期公开预览 · 源代码参见
|
||||||
<a href="https://github.com/alikia2x/aquavox">GitHub</a>
|
<a href="https://github.com/alikia2x/aquavox">GitHub</a>
|
||||||
</p>
|
</p>
|
||||||
<a href="/import">导入音乐</a> <br />
|
<a href="/import">导入音乐</a> <br />
|
||||||
|
Loading…
Reference in New Issue
Block a user