From 60fd80e1a702035edaf389de39ad1edba62fbead Mon Sep 17 00:00:00 2001 From: raotaohub Date: Tue, 6 Jun 2023 14:40:59 +0800 Subject: [PATCH] feat: drag the progress volume bar (#22) --- src/components/controller.tsx | 54 ++------- src/components/volume.tsx | 82 ++++++++++++++ src/utils/computePercentage.test.ts | 165 +++++++++++++++++++--------- src/utils/computePercentage.ts | 15 +++ 4 files changed, 221 insertions(+), 95 deletions(-) create mode 100644 src/components/volume.tsx diff --git a/src/components/controller.tsx b/src/components/controller.tsx index f75c549..d81997a 100644 --- a/src/components/controller.tsx +++ b/src/components/controller.tsx @@ -1,6 +1,3 @@ -import { ReactComponent as IconVolumeUp } from "../assets/volume-up.svg"; -import { ReactComponent as IconVolumeDown } from "../assets/volume-down.svg"; -import { ReactComponent as IconVolumeOff } from "../assets/volume-off.svg"; import { ReactComponent as IconMenu } from "../assets/menu.svg"; import { ReactComponent as IconOrderList } from "../assets/order-list.svg"; import { ReactComponent as IconOrderRandom } from "../assets/order-random.svg"; @@ -11,6 +8,7 @@ import { formatAudioDuration } from "../utils/formatAudioDuration"; import { ProgressBar } from "./progress"; import React, { useCallback } from "react"; import { PlaylistLoop, PlaylistOrder } from "../hooks/usePlaylist"; +import { Volume } from "./volume"; type PlaybackControlsProps = { themeColor: string; @@ -45,21 +43,6 @@ export function PlaybackControls({ onLoopChange, onSeek, }: PlaybackControlsProps) { - const handleVolumeBarMouseDown = useCallback( - (e: React.MouseEvent) => { - const volumeBarElement = e.currentTarget; - const volumeBarRect = volumeBarElement.getBoundingClientRect(); - - onChangeVolume( - Math.min( - 1, - Math.max(0, (volumeBarRect.bottom - e.clientY) / volumeBarRect.height) - ) - ); - }, - [onChangeVolume] - ); - // Switch order between "list" and "random" const handleOrderButtonClick = useCallback(() => { const nextOrder: PlaylistOrder = ( @@ -116,34 +99,13 @@ export function PlaybackControls({ -
- -
-
-
-
-
-
+ +
+
+
+
+
+ + ); +} diff --git a/src/utils/computePercentage.test.ts b/src/utils/computePercentage.test.ts index a1e9d36..7b45fd6 100644 --- a/src/utils/computePercentage.test.ts +++ b/src/utils/computePercentage.test.ts @@ -1,56 +1,123 @@ import { expect, test } from "vitest"; -import { computePercentage } from "./computePercentage"; +import { computePercentage, computePercentageOfY } from "./computePercentage"; +import { describe } from "vitest"; -test("Return 0 if progressBarRef.current is undefined", () => { - expect( - computePercentage(new MouseEvent("mouseup", {}), { current: null }) - ).toBe(0); -}); +describe("computePercentage", () => { + test("Return 0 if progressBarRef.current is undefined", () => { + expect( + computePercentage(new MouseEvent("mouseup", {}), { current: null }) + ).toBe(0); + }); -test("Return 0 if progressBarRef.current is undefined", () => { - expect( - computePercentage(new MouseEvent("mousemove"), { current: null }) - ).toBe(0); -}); + test("Return 0 if progressBarRef.current is undefined", () => { + expect( + computePercentage(new MouseEvent("mousemove"), { current: null }) + ).toBe(0); + }); + + test("Return 0 if progressBarRef.current is undefined", () => { + expect( + computePercentage(new MouseEvent("mousedown"), { + current: null, + }) + ).toBe(0); + }); + + describe("Given an valid percentage,when the mouse moves on the X axis", () => { + /* MOCK DOM */ + test("Return valid percentage,when input two valid Event Objet", () => { + const container = document.createElement("div"); + container.style.width = "200px"; + container.style.height = "2px"; + const mouseEvent = new MouseEvent("mousedown", { + clientX: 50, + clientY: 50, + }); + + /* hack ! no value in the node environment , so overwrite they */ + container.clientWidth = 200; + container.getBoundingClientRect = () => ({ + x: 10, + y: 10, + width: 300, + height: 2, + top: 10, + right: 300, + bottom: 10, + left: 10, + toJSON: function () { + return ""; + }, + }); -test("Return 0 if progressBarRef.current is undefined", () => { - expect( - computePercentage(new MouseEvent("mousedown"), { - current: null, - }) - ).toBe(0); + container.addEventListener("mousedown", function (e) { + const val = computePercentage(e, { current: container }); + expect(val).toBe(0.2); + }); + + container.dispatchEvent(mouseEvent); + }); + }); }); -/* MOCK DOM */ -test("Return percentage when mousedown event", () => { - const container = document.createElement("div"); - container.style.width = "200px"; - container.style.height = "2px"; - const mouseEvent = new MouseEvent("mousedown", { - clientX: 50, - clientY: 50, - }); - - /* hack ! no value in the node environment , so overwrite they */ - container.clientWidth = 200; - container.getBoundingClientRect = () => ({ - x: 10, - y: 10, - width: 300, - height: 2, - top: 10, - right: 300, - bottom: 10, - left: 10, - toJSON: function () { - return ""; - }, - }); - - container.addEventListener("mousedown", function (e) { - const val = computePercentage(e, { current: container }); - expect(val).toBe(0.2); - }); - - container.dispatchEvent(mouseEvent); +describe("computePercentageOfY", () => { + test("Return 0 if volumeBarRef.current is undefined", () => { + expect( + computePercentageOfY(new MouseEvent("mouseup"), { + current: null, + }) + ).toBe(0); + }); + + test("Return 0 if volumeBarRef.current is undefined", () => { + expect( + computePercentageOfY(new MouseEvent("mousemove"), { + current: null, + }) + ).toBe(0); + }); + + test("Return 0 if volumeBarRef.current is undefined", () => { + expect( + computePercentageOfY(new MouseEvent("mousedown"), { + current: null, + }) + ).toBe(0); + }); + + describe("Given an valid percentage,when the mouse moves on the Y axis", () => { + /* MOCK DOM */ + test("Return valid percentage,when input two valid Event Objet", () => { + const container = document.createElement("div"); + container.style.width = "10px"; + container.style.height = "300px"; + const mouseEvent = new MouseEvent("mousedown", { + clientX: 50, + clientY: 100, + }); + + /* hack ! no value in the node environment , so overwrite they */ + container.clientHeight = 300; + container.getBoundingClientRect = () => ({ + x: 10, + y: 10, + width: 50, + height: 300, + top: 10, + right: 300, + bottom: 10, + left: 10, + toJSON: function () { + return ""; + }, + }); + + container.addEventListener("mousedown", function (e) { + const val = computePercentageOfY(e, { current: container }); + expect(val).toBe(0.7); + }); + + container.dispatchEvent(mouseEvent); + }); + }); }); diff --git a/src/utils/computePercentage.ts b/src/utils/computePercentage.ts index ab58c71..b0f63ec 100644 --- a/src/utils/computePercentage.ts +++ b/src/utils/computePercentage.ts @@ -12,3 +12,18 @@ export function computePercentage( percentage = Math.floor(percentage * 100) / 100; return percentage; } + +export function computePercentageOfY( + eventTarget: Pick, + volumeBarRef: React.RefObject +) { + if (!volumeBarRef.current) return 0; + let percentage = + 1 - + (eventTarget.clientY - volumeBarRef.current.getBoundingClientRect().top) / + volumeBarRef.current.clientHeight; + percentage = Math.max(percentage, 0); + percentage = Math.min(percentage, 1); + percentage = Math.floor(percentage * 100) / 100; + return percentage; +}