diff --git a/apps/client/src/widgets/type_widgets/file/Audio.tsx b/apps/client/src/widgets/type_widgets/file/Audio.tsx
index ffd83b5e51..32b67ac1b3 100644
--- a/apps/client/src/widgets/type_widgets/file/Audio.tsx
+++ b/apps/client/src/widgets/type_widgets/file/Audio.tsx
@@ -3,7 +3,7 @@ import { useRef, useState } from "preact/hooks";
import FNote from "../../../entities/fnote";
import { t } from "../../../services/i18n";
import { getUrlForDownload } from "../../../services/open";
-import { PlayPauseButton, SeekBar, SkipButton, VolumeControl } from "./MediaPlayer";
+import { LoopButton, PlayPauseButton, SeekBar, SkipButton, VolumeControl } from "./MediaPlayer";
export default function AudioPreview({ note }: { note: FNote }) {
const [playing, setPlaying] = useState(false);
@@ -25,9 +25,11 @@ export default function AudioPreview({ note }: { note: FNote }) {
diff --git a/apps/client/src/widgets/type_widgets/file/MediaPlayer.tsx b/apps/client/src/widgets/type_widgets/file/MediaPlayer.tsx
index 6049a53ee6..6985773214 100644
--- a/apps/client/src/widgets/type_widgets/file/MediaPlayer.tsx
+++ b/apps/client/src/widgets/type_widgets/file/MediaPlayer.tsx
@@ -146,3 +146,33 @@ export function SkipButton({ mediaRef, seconds, icon, text }: { mediaRef: RefObj
);
}
+
+export function LoopButton({ mediaRef }: { mediaRef: RefObject
}) {
+ const [loop, setLoop] = useState(() => mediaRef.current?.loop ?? false);
+
+ useEffect(() => {
+ const media = mediaRef.current;
+ if (!media) return;
+ setLoop(media.loop);
+
+ const observer = new MutationObserver(() => setLoop(media.loop));
+ observer.observe(media, { attributes: true, attributeFilter: ["loop"] });
+ return () => observer.disconnect();
+ }, []);
+
+ const toggle = () => {
+ const media = mediaRef.current;
+ if (!media) return;
+ media.loop = !media.loop;
+ setLoop(media.loop);
+ };
+
+ return (
+
+ );
+}
diff --git a/apps/client/src/widgets/type_widgets/file/Video.tsx b/apps/client/src/widgets/type_widgets/file/Video.tsx
index c22725f70e..41654140fc 100644
--- a/apps/client/src/widgets/type_widgets/file/Video.tsx
+++ b/apps/client/src/widgets/type_widgets/file/Video.tsx
@@ -10,7 +10,7 @@ import ActionButton from "../../react/ActionButton";
import Dropdown from "../../react/Dropdown";
import Icon from "../../react/Icon";
import NoItems from "../../react/NoItems";
-import { PlayPauseButton, SeekBar, SkipButton, VolumeControl } from "./MediaPlayer";
+import { LoopButton, PlayPauseButton, SeekBar, SkipButton, VolumeControl } from "./MediaPlayer";
const AUTO_HIDE_DELAY = 3000;
@@ -125,7 +125,7 @@ export default function VideoPreview({ note }: { note: FNote }) {
-
+
@@ -217,36 +217,6 @@ function PlaybackSpeed({ videoRef }: { videoRef: RefObject
})
);
}
-function LoopButton({ videoRef }: { videoRef: RefObject }) {
- const [loop, setLoop] = useState(() => videoRef.current?.loop ?? false);
-
- useEffect(() => {
- const video = videoRef.current;
- if (!video) return;
- setLoop(video.loop);
-
- const observer = new MutationObserver(() => setLoop(video.loop));
- observer.observe(video, { attributes: true, attributeFilter: ["loop"] });
- return () => observer.disconnect();
- }, []);
-
- const toggle = () => {
- const video = videoRef.current;
- if (!video) return;
- video.loop = !video.loop;
- setLoop(video.loop);
- };
-
- return (
-
- );
-}
-
function RotateButton({ videoRef }: { videoRef: RefObject }) {
const [rotation, setRotation] = useState(0);