block global audio from screens
This commit is contained in:
@@ -56,6 +56,26 @@ const App = () => {
|
|||||||
|
|
||||||
const [isInitializing, setInitializing] = useState(true);
|
const [isInitializing, setInitializing] = useState(true);
|
||||||
|
|
||||||
|
const routeNameRef = React.useRef(null);
|
||||||
|
|
||||||
|
const syncActiveRoute = useCallback(() => {
|
||||||
|
const currentRoute = navigationRef.current?.getCurrentRoute();
|
||||||
|
const currentName = currentRoute?.name ?? null;
|
||||||
|
|
||||||
|
if (routeNameRef.current !== currentName) {
|
||||||
|
routeNameRef.current = currentName;
|
||||||
|
setGlobal({ activeRouteName: currentName });
|
||||||
|
}
|
||||||
|
}, [setGlobal]);
|
||||||
|
|
||||||
|
const handleNavigationReady = useCallback(() => {
|
||||||
|
syncActiveRoute();
|
||||||
|
}, [syncActiveRoute]);
|
||||||
|
|
||||||
|
const handleNavigationStateChange = useCallback(() => {
|
||||||
|
syncActiveRoute();
|
||||||
|
}, [syncActiveRoute]);
|
||||||
|
|
||||||
const [loaded] = useFonts({
|
const [loaded] = useFonts({
|
||||||
NewYorkSemibold: require("./src/assets/fonts/NewYork-Semibold.ttf"),
|
NewYorkSemibold: require("./src/assets/fonts/NewYork-Semibold.ttf"),
|
||||||
OpenSansRegular: require("./src/assets/fonts/OpenSans-Regular.ttf"),
|
OpenSansRegular: require("./src/assets/fonts/OpenSans-Regular.ttf"),
|
||||||
@@ -164,6 +184,8 @@ const App = () => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
ref={navigationRef}
|
ref={navigationRef}
|
||||||
|
onReady={handleNavigationReady}
|
||||||
|
onStateChange={handleNavigationStateChange}
|
||||||
documentTitle={{
|
documentTitle={{
|
||||||
formatter: (options) =>
|
formatter: (options) =>
|
||||||
options?.title
|
options?.title
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ exports.SUNO_API_PATH = "/api/v1/generate";
|
|||||||
exports.SUNO_STATUS_PATH = "/api/v1/generate/record-info";
|
exports.SUNO_STATUS_PATH = "/api/v1/generate/record-info";
|
||||||
exports.SUNO_TIMESTAMPED_LYRICS_PATH =
|
exports.SUNO_TIMESTAMPED_LYRICS_PATH =
|
||||||
"/api/v1/generate/get-timestamped-lyrics";
|
"/api/v1/generate/get-timestamped-lyrics";
|
||||||
exports.SUNO_MODEL = "V4_5";
|
exports.SUNO_MODEL = "V5";
|
||||||
exports.SUNO_CALLBACK_URL =
|
exports.SUNO_CALLBACK_URL =
|
||||||
"https://us-central1-musicland-d33f9.cloudfunctions.net/music-sunoCallback";
|
"https://us-central1-musicland-d33f9.cloudfunctions.net/music-sunoCallback";
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ export default {
|
|||||||
currentUserData: null,
|
currentUserData: null,
|
||||||
currentUserRoles: [],
|
currentUserRoles: [],
|
||||||
|
|
||||||
|
activeRouteName: null,
|
||||||
|
|
||||||
webBackgroundImg: null,
|
webBackgroundImg: null,
|
||||||
webLayoutMode: "default",
|
webLayoutMode: "default",
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,46 @@ import React, {
|
|||||||
} from "react";
|
} from "react";
|
||||||
import { Platform } from "react-native";
|
import { Platform } from "react-native";
|
||||||
import { useAudioPlayer, useAudioPlayerStatus } from "expo-audio";
|
import { useAudioPlayer, useAudioPlayerStatus } from "expo-audio";
|
||||||
|
import { useGlobal } from "reactn";
|
||||||
|
|
||||||
import GlobalAudioPlayer from "../components/player/GlobalAudioPlayer";
|
import GlobalAudioPlayer from "../components/player/GlobalAudioPlayer";
|
||||||
|
import { Routes } from "../navigation/Routes";
|
||||||
|
|
||||||
|
const HIDDEN_ROUTE_NAMES = new Set([
|
||||||
|
Routes.Writing,
|
||||||
|
Routes.WritingLyrics,
|
||||||
|
Routes.CreateLyricsWithAi,
|
||||||
|
Routes.Lyrics,
|
||||||
|
Routes.FinishedWriting,
|
||||||
|
Routes.Studio,
|
||||||
|
Routes.Compose,
|
||||||
|
Routes.ComposeSong,
|
||||||
|
Routes.CustomizeVoice,
|
||||||
|
Routes.SongReady,
|
||||||
|
Routes.Regenerate,
|
||||||
|
Routes.PouchReady,
|
||||||
|
Routes.PhotoCover,
|
||||||
|
Routes.ValidateCover,
|
||||||
|
Routes.FinishCompose,
|
||||||
|
Routes.GeneratingSong,
|
||||||
|
Routes.ProductionOnboarding,
|
||||||
|
Routes.Production,
|
||||||
|
Routes.DownloadSongs,
|
||||||
|
Routes.DownloadPrices,
|
||||||
|
Routes.SongDownloaded,
|
||||||
|
Routes.StreamSong,
|
||||||
|
Routes.SongRelease,
|
||||||
|
Routes.PlaybackExample,
|
||||||
|
Routes.PlaybackOnboarding,
|
||||||
|
Routes.Playback,
|
||||||
|
Routes.RecordPlayback,
|
||||||
|
Routes.RecordedPlayback,
|
||||||
|
Routes.ChooseDecor,
|
||||||
|
Routes.CreatingDecor,
|
||||||
|
Routes.VideoFinalize,
|
||||||
|
Routes.FlowSelection,
|
||||||
|
Routes.ChooseCoverType,
|
||||||
|
]);
|
||||||
|
|
||||||
const noopAsync = async () => {};
|
const noopAsync = async () => {};
|
||||||
const noop = () => {};
|
const noop = () => {};
|
||||||
@@ -23,6 +61,7 @@ const DEFAULT_CONTEXT = {
|
|||||||
positionMs: 0,
|
positionMs: 0,
|
||||||
durationMs: 0,
|
durationMs: 0,
|
||||||
error: null,
|
error: null,
|
||||||
|
isPlayerVisible: true,
|
||||||
play: noopAsync,
|
play: noopAsync,
|
||||||
togglePlay: noopAsync,
|
togglePlay: noopAsync,
|
||||||
pause: noopAsync,
|
pause: noopAsync,
|
||||||
@@ -146,6 +185,7 @@ const normalizeTrack = (trackInput = {}, options = {}) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const PlayerProvider = ({ children }) => {
|
const PlayerProvider = ({ children }) => {
|
||||||
|
const [activeRouteName] = useGlobal("activeRouteName");
|
||||||
const [currentTrack, setCurrentTrack] = useState(null);
|
const [currentTrack, setCurrentTrack] = useState(null);
|
||||||
const [queue, setQueue] = useState([]);
|
const [queue, setQueue] = useState([]);
|
||||||
const [playback, setPlayback] = useState({
|
const [playback, setPlayback] = useState({
|
||||||
@@ -167,6 +207,9 @@ const PlayerProvider = ({ children }) => {
|
|||||||
|
|
||||||
const player = useAudioPlayer(source || null, 200);
|
const player = useAudioPlayer(source || null, 200);
|
||||||
const status = useAudioPlayerStatus(player);
|
const status = useAudioPlayerStatus(player);
|
||||||
|
const shouldHideOnRoute = activeRouteName
|
||||||
|
? HIDDEN_ROUTE_NAMES.has(activeRouteName)
|
||||||
|
: false;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!status) return;
|
if (!status) return;
|
||||||
@@ -392,6 +435,7 @@ const PlayerProvider = ({ children }) => {
|
|||||||
positionMs: playback.positionMs,
|
positionMs: playback.positionMs,
|
||||||
durationMs: playback.durationMs,
|
durationMs: playback.durationMs,
|
||||||
error,
|
error,
|
||||||
|
isPlayerVisible: !shouldHideOnRoute,
|
||||||
play,
|
play,
|
||||||
togglePlay,
|
togglePlay,
|
||||||
pause,
|
pause,
|
||||||
@@ -415,6 +459,7 @@ const PlayerProvider = ({ children }) => {
|
|||||||
resume,
|
resume,
|
||||||
seekBy,
|
seekBy,
|
||||||
seekTo,
|
seekTo,
|
||||||
|
shouldHideOnRoute,
|
||||||
stop,
|
stop,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -422,7 +467,7 @@ const PlayerProvider = ({ children }) => {
|
|||||||
return (
|
return (
|
||||||
<PlayerContext.Provider value={contextValue}>
|
<PlayerContext.Provider value={contextValue}>
|
||||||
{children}
|
{children}
|
||||||
<GlobalAudioPlayer />
|
{!shouldHideOnRoute && <GlobalAudioPlayer />}
|
||||||
</PlayerContext.Provider>
|
</PlayerContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export default ({ children }) => {
|
|||||||
const { setIsLoading, setTooltip } = useMinuit();
|
const { setIsLoading, setTooltip } = useMinuit();
|
||||||
|
|
||||||
const [pendingUserData, setPendingUserData] = useState({
|
const [pendingUserData, setPendingUserData] = useState({
|
||||||
creationTimestamp: new Date(),
|
createdAt: new Date(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const [currentUID] = useGlobal("currentUID");
|
const [currentUID] = useGlobal("currentUID");
|
||||||
@@ -292,8 +292,8 @@ export default ({ children }) => {
|
|||||||
userID: dynamicUID,
|
userID: dynamicUID,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!cleanData?.creationTimestamp) {
|
if (!cleanData?.createdAt) {
|
||||||
cleanData.creationTimestamp = new Date();
|
cleanData.createdAt = firebase.firestore.FieldValue.serverTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
await usersRef.doc(dynamicUID).set(cleanData, { merge: true });
|
await usersRef.doc(dynamicUID).set(cleanData, { merge: true });
|
||||||
|
|||||||
@@ -2,21 +2,19 @@ import React, { useCallback, useState } from "react";
|
|||||||
import { Image, StyleSheet, View } from "react-native";
|
import { Image, StyleSheet, View } from "react-native";
|
||||||
import { ai, background } from "../../assets";
|
import { ai, background } from "../../assets";
|
||||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||||
|
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
||||||
import GradientButton from "../../components/GradientButton";
|
import GradientButton from "../../components/GradientButton";
|
||||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||||
import Page from "../../layouts/Page";
|
import Page from "../../layouts/Page";
|
||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||||
import { gutters } from "../../styles";
|
import { gutters } from "../../styles";
|
||||||
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
|
||||||
|
|
||||||
const Playback = ({ route }) => {
|
const Playback = ({ route }) => {
|
||||||
const { project } = route.params;
|
const { project } = route.params;
|
||||||
const [showIntro, setShowIntro] = useState(true);
|
const [showIntro, setShowIntro] = useState(true);
|
||||||
|
|
||||||
const onPressRecord = useCallback(() => {
|
const onPressRecord = useCallback(() => {
|
||||||
// Les timestamps sont désormais générés automatiquement côté serveur
|
|
||||||
// lors de la mise à jour du document (si songUrl existe).
|
|
||||||
navigate(Routes.RecordPlayback, { project });
|
navigate(Routes.RecordPlayback, { project });
|
||||||
}, [project]);
|
}, [project]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useFocusEffect } from "@react-navigation/native";
|
import { useFocusEffect } from "@react-navigation/native";
|
||||||
import useSharedAudioPlayer from "../../hooks/useSharedAudioPlayer";
|
|
||||||
import { CameraView, useCameraPermissions } from "expo-camera";
|
import { CameraView, useCameraPermissions } from "expo-camera";
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
@@ -11,11 +10,12 @@ import React, {
|
|||||||
import { Text, View } from "react-native";
|
import { Text, View } from "react-native";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import Svg, { Circle } from "react-native-svg";
|
import Svg, { Circle } from "react-native-svg";
|
||||||
|
import alert from "../../components/Alert";
|
||||||
import GradientButton from "../../components/GradientButton";
|
import GradientButton from "../../components/GradientButton";
|
||||||
import KaraokeLyrics from "../../components/KaraokeLyrics";
|
import KaraokeLyrics from "../../components/KaraokeLyrics";
|
||||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||||
import alert from "../../components/Alert";
|
|
||||||
import { increment, projectsRef } from "../../config/firebase";
|
import { increment, projectsRef } from "../../config/firebase";
|
||||||
|
import useSharedAudioPlayer from "../../hooks/useSharedAudioPlayer";
|
||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||||
import { gutters, Palette } from "../../styles";
|
import { gutters, Palette } from "../../styles";
|
||||||
@@ -27,6 +27,7 @@ const TIME_BEFORE_INCREMENT_MS = 20000; // 20s
|
|||||||
const RecordPlayback = ({ route }) => {
|
const RecordPlayback = ({ route }) => {
|
||||||
const { top, bottom } = useSafeAreaInsets();
|
const { top, bottom } = useSafeAreaInsets();
|
||||||
const { project } = route.params || {};
|
const { project } = route.params || {};
|
||||||
|
console.log("project is : ", JSON.stringify(project, null, 2));
|
||||||
const projectId = project?.id;
|
const projectId = project?.id;
|
||||||
const songIndex = project?.songIndex;
|
const songIndex = project?.songIndex;
|
||||||
// Permissions
|
// Permissions
|
||||||
@@ -55,9 +56,14 @@ const RecordPlayback = ({ route }) => {
|
|||||||
// Musique
|
// Musique
|
||||||
const songUrl = project?.songUrl || null;
|
const songUrl = project?.songUrl || null;
|
||||||
const player = useSharedAudioPlayer(songUrl ? { uri: songUrl } : undefined, {
|
const player = useSharedAudioPlayer(songUrl ? { uri: songUrl } : undefined, {
|
||||||
id: projectId ? `record-${projectId}` : songUrl ? `record-${songUrl}` : undefined,
|
id: projectId
|
||||||
|
? `record-${projectId}`
|
||||||
|
: songUrl
|
||||||
|
? `record-${songUrl}`
|
||||||
|
: undefined,
|
||||||
title: typeof project?.title === "string" ? project.title : "Sans titre",
|
title: typeof project?.title === "string" ? project.title : "Sans titre",
|
||||||
artist: typeof project?.userName === "string" ? project.userName : "MusicLand",
|
artist:
|
||||||
|
typeof project?.userName === "string" ? project.userName : "MusicLand",
|
||||||
artwork: project?.coverUrl || null,
|
artwork: project?.coverUrl || null,
|
||||||
coverUrl: project?.coverUrl || null,
|
coverUrl: project?.coverUrl || null,
|
||||||
metadata: { projectId, screen: "RecordPlayback" },
|
metadata: { projectId, screen: "RecordPlayback" },
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useFocusEffect } from "@react-navigation/native";
|
import { useFocusEffect } from "@react-navigation/native";
|
||||||
import useSharedAudioPlayer from "../../hooks/useSharedAudioPlayer";
|
|
||||||
import { useCameraPermissions } from "expo-camera";
|
import { useCameraPermissions } from "expo-camera";
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
@@ -11,12 +10,13 @@ import React, {
|
|||||||
import { Text, View } from "react-native";
|
import { Text, View } from "react-native";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import Svg, { Circle } from "react-native-svg";
|
import Svg, { Circle } from "react-native-svg";
|
||||||
|
import alert from "../../components/Alert";
|
||||||
import GradientButton from "../../components/GradientButton";
|
import GradientButton from "../../components/GradientButton";
|
||||||
import KaraokeLyrics from "../../components/KaraokeLyrics";
|
import KaraokeLyrics from "../../components/KaraokeLyrics";
|
||||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||||
import alert from "../../components/Alert";
|
|
||||||
import { increment, projectsRef } from "../../config/firebase";
|
import { increment, projectsRef } from "../../config/firebase";
|
||||||
import { isWeb } from "../../hooks/useLayoutType";
|
import { isWeb } from "../../hooks/useLayoutType";
|
||||||
|
import useSharedAudioPlayer from "../../hooks/useSharedAudioPlayer";
|
||||||
import Page from "../../layouts/Page";
|
import Page from "../../layouts/Page";
|
||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||||
@@ -62,12 +62,13 @@ const RecordPlayback = ({ route }) => {
|
|||||||
// Player
|
// Player
|
||||||
const songUrl = project?.songUrl || null;
|
const songUrl = project?.songUrl || null;
|
||||||
const player = useSharedAudioPlayer(songUrl ? { uri: songUrl } : undefined, {
|
const player = useSharedAudioPlayer(songUrl ? { uri: songUrl } : undefined, {
|
||||||
id: projectId ? `record-${projectId}` : songUrl ? `record-${songUrl}` : undefined,
|
id: project?.id,
|
||||||
title: typeof project?.title === "string" ? project.title : "Sans titre",
|
title: typeof project?.title === "string" ? project.title : "Sans titre",
|
||||||
artist: typeof project?.userName === "string" ? project.userName : "MusicLand",
|
artist:
|
||||||
|
typeof project?.userName === "string" ? project.userName : "MusicLand",
|
||||||
artwork: project?.coverUrl || null,
|
artwork: project?.coverUrl || null,
|
||||||
coverUrl: project?.coverUrl || null,
|
coverUrl: project?.coverUrl || null,
|
||||||
metadata: { projectId, screen: "RecordPlayback" },
|
metadata: { projectId: project?.id, screen: "RecordPlayback" },
|
||||||
});
|
});
|
||||||
|
|
||||||
// MediaStream / Recorder (web only)
|
// MediaStream / Recorder (web only)
|
||||||
|
|||||||
Reference in New Issue
Block a user