diff --git a/src/WholeApp.js b/src/WholeApp.js index 0c86c9a..3b59740 100644 --- a/src/WholeApp.js +++ b/src/WholeApp.js @@ -10,6 +10,7 @@ import scales from "./data/scalesObj"; import { MobileView } from 'react-device-detect'; import Popup from 'reactjs-popup'; import SoundLibraryNames from "data/TonejsSoundNames"; +import * as Tone from "tone"; // TODO:to meet the requirements for router-dom v6 useParam hook can not be used in class Components and props.match.params only works in v5: //This is using a wrapper function for wholeApp because wholeApp is a class and not a functional component, REWRITE wholeApp to a const wholeApp =()=>{...} @@ -362,6 +363,19 @@ class WholeApp extends Component { // }); // } + // Safari audio fix - resume audio context on first user interaction + resumeAudioContext = async () => { + if (Tone.context.state !== "running") { + await Tone.context.resume(); + await Tone.start(); + console.log("Audio context resumed for Safari"); + } + // Remove listeners after first interaction + document.removeEventListener("click", this.resumeAudioContext); + document.removeEventListener("touchstart", this.resumeAudioContext); + document.removeEventListener("keydown", this.resumeAudioContext); + }; + componentDidMount() { /** * disable right click @@ -370,6 +384,11 @@ class WholeApp extends Component { return false; }; + // Safari/iOS audio fix - add listeners to resume audio context on first user interaction + document.addEventListener("click", this.resumeAudioContext); + document.addEventListener("touchstart", this.resumeAudioContext); + document.addEventListener("keydown", this.resumeAudioContext); + // const { match } = this.props; // const { params } = match; @@ -396,6 +415,13 @@ class WholeApp extends Component { */ } + componentWillUnmount() { + // Cleanup Safari audio fix listeners + document.removeEventListener("click", this.resumeAudioContext); + document.removeEventListener("touchstart", this.resumeAudioContext); + document.removeEventListener("keydown", this.resumeAudioContext); + } + toggleMenu = () => { this.setState({ menuOpen: !this.state.menuOpen }); }; @@ -470,17 +496,25 @@ class WholeApp extends Component { /> -
- } modal open={true} closeOnDocumentClick={false}> -
-

Notio does not have mobile support yet.

-

Please use a computer

+ } + > +
+

Notio has limited mobile support.

+

Please use a computer for the best experience.

diff --git a/src/components/menu/CustomVideoPlayer.js b/src/components/menu/CustomVideoPlayer.js index af92f10..da8abef 100644 --- a/src/components/menu/CustomVideoPlayer.js +++ b/src/components/menu/CustomVideoPlayer.js @@ -4,21 +4,6 @@ import ReactPlayer from "react-player/lazy"; import { Tabs, Tab, Form, Button } from "react-bootstrap"; import Overlay from "../OverlayPlugins/Overlay"; -/** - * CustomVideoPlayer - A customizable video player component - * - * Displays video content in an overlay/modal with: - * - Default URL from settings (US1) - * - Custom URL entry (US2) - * - Reset to default functionality (US3) - * - Draggable overlay display (US4) - * - * @param {string} defaultVideoUrl - Required. The original default video URL (used for reset) - * @param {string} currentVideoUrl - Optional. The current video URL to display - * @param {function} onClose - Required. Callback when overlay closes - * @param {string} initialTab - Optional. Initial tab to display ('Player' or 'Enter_url') - * @param {function} onUrlChange - Optional. Callback when video URL changes - */ // Helper to detect ReverbNation URLs const isReverbNationUrl = (url) => { return url && url.includes("reverbnation.com"); @@ -64,18 +49,20 @@ const getYouTubePlaylistEmbedUrl = (url) => { return url; }; -// Get ReactPlayer config based on URL type -const getPlayerConfig = (url) => { - return { - youtube: { - playerVars: { - modestbranding: 1, - rel: 0, - }, +// ReactPlayer config for YouTube +const PLAYER_CONFIG = { + youtube: { + playerVars: { + modestbranding: 1, + rel: 0, }, - }; + }, }; +/** + * CustomVideoPlayer - A customizable video player component + * Supports YouTube, Vimeo, direct video files, YouTube playlists, and ReverbNation + */ const CustomVideoPlayer = (props) => { const { defaultVideoUrl, currentVideoUrl, onClose, initialTab, onUrlChange } = props; @@ -89,9 +76,8 @@ const CustomVideoPlayer = (props) => { const isReverbNation = isReverbNationUrl(currentUrl); const isPlaylistOnly = isYouTubePlaylistOnly(currentUrl); - // US1: onReady handler + // US1: onReady handler - don't auto-play to avoid audio context conflicts const handlePlayerReady = () => { - setIsPlaying(true); setError(null); }; @@ -167,7 +153,6 @@ const CustomVideoPlayer = (props) => { frameBorder="0" scrolling="no" title="ReverbNation Player" - allow="autoplay" style={{ minHeight: "300px" }} /> ) : isPlaylistOnly ? ( @@ -178,7 +163,7 @@ const CustomVideoPlayer = (props) => { height="100%" frameBorder="0" title="YouTube Playlist" - allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" + allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen style={{ minHeight: "300px" }} /> @@ -192,7 +177,7 @@ const CustomVideoPlayer = (props) => { controls={true} onReady={handlePlayerReady} onError={handlePlayerError} - config={getPlayerConfig(currentUrl)} + config={PLAYER_CONFIG} /> )} {error && !isReverbNation && !isPlaylistOnly && ( diff --git a/src/components/menu/VideoTutorial.js b/src/components/menu/VideoTutorial.js deleted file mode 100644 index be94b59..0000000 --- a/src/components/menu/VideoTutorial.js +++ /dev/null @@ -1,203 +0,0 @@ -import React, { useRef, useState } from "react"; -import ReactPlayer from "react-player/lazy"; -import { Tabs, Tab, Form, Button } from "react-bootstrap"; - -import Overlay from "./../OverlayPlugins/Overlay"; - -const VideoTutorial = (props) => { - const urlInputRef = useRef(); - const [playing, setPlaying] = useState(false); - const [videoUrl, setVideoUrl] = useState(props.videoUrl); - const [activeTab, setActiveTab] = useState(props.activeVideoTab); - - // TODO:use this : handleChangeActiveVideoTab={this.props.handleChangeActiveVideoTab}, when a tab is selected to persist the selection - const tabKeys = ["Player", "Enter_url", "Tutorials"]; - - const handleSubmit = (event) => { - event.preventDefault(); - setVideoUrl(event.target.elements[0].value); - props.handleChangeVideoUrl(event.target.elements[0].value); - props.handleChangeActiveVideoTab("Player"); - setActiveTab("Player"); - }; - - // //this can be used if we make the tabs controlled - const handleTabSelected = (key) => { - // A bit dummy but need to control tabs after submit (cf handleSumbit()) - - if (tabKeys.includes(key)) { - setActiveTab(key); - props.handleChangeActiveVideoTab(key); - } - // if (key === "Player") { - // setActiveTab("Player"); - // props.handleChangeActiveVideoTab("Player") - // // this.setState({ activeTab: "Player" }); - // } - // if (key === "Enter_url") { - // setActiveTab("Enter_url"); - // props.handleChangeActiveVideoTab("Enter_url") - - // // this.setState({ activeTab: "Enter_url" }); - // } - }; - - const playerOnReady = (event) => { - // A bit dummy but need to control tabs after submit (cf handleSumbit()) - // setPlayerIsReady(false); - setPlaying(true); - }; - - const resetVideoUrl = (event) => { - console.log(props.resetVideoUrl); - setVideoUrl(props.resetVideoUrl); - props.handleResetVideoUrl(); - setActiveTab("Player"); - }; - - return ( - - {/* */} - -
- {/* */} - {/* */} - - - - - - -
-
- - Video URL - - - - - Enter the URL for any YouTube video or playlist that you want to use with - Notio and hit Enter. - - - You are currently watching: - {props.videoUrl} - - {/* Current URL: {videoUrl} */} - - - -
-
-
- -
-
-
Keyboard on/off
- -
- -
-
Notation
- -
- -
-
Ambitus
- -
- -
-
Select different scales
- -
- -
-
Video player
- -
- -
-
Share your setup
- -
-
-
-
-
-
-
- ); -}; - -export default VideoTutorial;