feat: continue music when app is closed
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
|||||||
@@ -37,6 +37,9 @@
|
|||||||
],
|
],
|
||||||
"bundleIdentifier": "com.omedis.musicland.ai",
|
"bundleIdentifier": "com.omedis.musicland.ai",
|
||||||
"infoPlist": {
|
"infoPlist": {
|
||||||
|
"UIBackgroundModes": [
|
||||||
|
"audio"
|
||||||
|
],
|
||||||
"NSMicrophoneUsageDescription": "MusicLand uses the microphone to record your voice and audio so you can create and collaborate on music projects.",
|
"NSMicrophoneUsageDescription": "MusicLand uses the microphone to record your voice and audio so you can create and collaborate on music projects.",
|
||||||
"UISupportedInterfaceOrientations": [
|
"UISupportedInterfaceOrientations": [
|
||||||
"UIInterfaceOrientationPortrait",
|
"UIInterfaceOrientationPortrait",
|
||||||
@@ -73,7 +76,9 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
"android.permission.CAMERA",
|
"android.permission.CAMERA",
|
||||||
"android.permission.MODIFY_AUDIO_SETTINGS",
|
"android.permission.MODIFY_AUDIO_SETTINGS",
|
||||||
"android.permission.POST_NOTIFICATIONS"
|
"android.permission.POST_NOTIFICATIONS",
|
||||||
|
"android.permission.WAKE_LOCK",
|
||||||
|
"android.permission.FOREGROUND_SERVICE"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"web": {
|
"web": {
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
"expo-linear-gradient": "~14.0.2",
|
"expo-linear-gradient": "~14.0.2",
|
||||||
"expo-linking": "~7.0.5",
|
"expo-linking": "~7.0.5",
|
||||||
"expo-location": "~18.0.10",
|
"expo-location": "~18.0.10",
|
||||||
"expo-minuit-shake-report": "^0.1.1",
|
|
||||||
"expo-notifications": "~0.29.14",
|
"expo-notifications": "~0.29.14",
|
||||||
"expo-sharing": "~13.0.1",
|
"expo-sharing": "~13.0.1",
|
||||||
"expo-speech": "~13.0.1",
|
"expo-speech": "~13.0.1",
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { useAudioPlayer, useAudioPlayerStatus } from "expo-audio";
|
import {
|
||||||
|
setAudioModeAsync,
|
||||||
|
useAudioPlayer,
|
||||||
|
useAudioPlayerStatus,
|
||||||
|
} from "expo-audio";
|
||||||
import React, {
|
import React, {
|
||||||
createContext,
|
createContext,
|
||||||
useCallback,
|
useCallback,
|
||||||
@@ -63,8 +67,8 @@ const HIDDEN_ROUTE_NAMES = new Set([
|
|||||||
Routes.Register,
|
Routes.Register,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const noopAsync = async () => {};
|
const noopAsync = async () => { };
|
||||||
const noop = () => {};
|
const noop = () => { };
|
||||||
|
|
||||||
const DEFAULT_CONTEXT = {
|
const DEFAULT_CONTEXT = {
|
||||||
currentTrack: null,
|
currentTrack: null,
|
||||||
@@ -274,36 +278,36 @@ const PlayerProvider = ({ children }) => {
|
|||||||
(items = [], options = {}) => {
|
(items = [], options = {}) => {
|
||||||
const normalized = Array.isArray(items)
|
const normalized = Array.isArray(items)
|
||||||
? items
|
? items
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
if (typeof item === "object") {
|
if (typeof item === "object") {
|
||||||
const { metadata, context, ...rest } = item;
|
const { metadata, context, ...rest } = item;
|
||||||
const safeMetadata =
|
const safeMetadata =
|
||||||
metadata && typeof metadata === "object"
|
metadata && typeof metadata === "object"
|
||||||
? { ...metadata }
|
? { ...metadata }
|
||||||
: undefined;
|
: undefined;
|
||||||
if (safeMetadata) {
|
if (safeMetadata) {
|
||||||
delete safeMetadata.queue;
|
delete safeMetadata.queue;
|
||||||
}
|
|
||||||
const safeContext =
|
|
||||||
context && typeof context === "object"
|
|
||||||
? { ...context }
|
|
||||||
: undefined;
|
|
||||||
if (safeContext) {
|
|
||||||
delete safeContext.queue;
|
|
||||||
}
|
|
||||||
return normalizeTrack(
|
|
||||||
{
|
|
||||||
...rest,
|
|
||||||
...(safeMetadata ? { metadata: safeMetadata } : {}),
|
|
||||||
...(safeContext ? { context: safeContext } : {}),
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return normalizeTrack(item, {});
|
const safeContext =
|
||||||
})
|
context && typeof context === "object"
|
||||||
.filter((track) => !!track?.source)
|
? { ...context }
|
||||||
|
: undefined;
|
||||||
|
if (safeContext) {
|
||||||
|
delete safeContext.queue;
|
||||||
|
}
|
||||||
|
return normalizeTrack(
|
||||||
|
{
|
||||||
|
...rest,
|
||||||
|
...(safeMetadata ? { metadata: safeMetadata } : {}),
|
||||||
|
...(safeContext ? { context: safeContext } : {}),
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return normalizeTrack(item, {});
|
||||||
|
})
|
||||||
|
.filter((track) => !!track?.source)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
queueRef.current = normalized;
|
queueRef.current = normalized;
|
||||||
@@ -374,6 +378,18 @@ const PlayerProvider = ({ children }) => {
|
|||||||
return Platform.OS === "web" ? ms : ms / 1000;
|
return Platform.OS === "web" ? ms : ms / 1000;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAudioModeAsync({
|
||||||
|
playsInSilentMode: true,
|
||||||
|
shouldPlayInBackground: true,
|
||||||
|
interruptionMode: "doNotMix",
|
||||||
|
allowsRecording: false,
|
||||||
|
shouldRouteThroughEarpiece: false,
|
||||||
|
}).catch((err) =>
|
||||||
|
console.warn("PlayerProvider: impossible de configurer le mode audio", err)
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!status) return;
|
if (!status) return;
|
||||||
|
|
||||||
@@ -450,7 +466,7 @@ const PlayerProvider = ({ children }) => {
|
|||||||
if (!player) return;
|
if (!player) return;
|
||||||
try {
|
try {
|
||||||
player.loop = !!isLooping;
|
player.loop = !!isLooping;
|
||||||
} catch (_err) {}
|
} catch (_err) { }
|
||||||
}, [player, isLooping]);
|
}, [player, isLooping]);
|
||||||
|
|
||||||
const seekDebounceRef = useRef(null);
|
const seekDebounceRef = useRef(null);
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { ShakeReportProvider } from "expo-minuit-shake-report";
|
|
||||||
import SharedProviders from "./SharedProviders";
|
import SharedProviders from "./SharedProviders";
|
||||||
|
|
||||||
export default ({ children }) => {
|
export default ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<ShakeReportProvider projectID="musicland" defaultEmail="user@email.com">
|
// <ShakeReportProvider projectID="musicland" defaultEmail="user@email.com">
|
||||||
<SharedProviders>{children}</SharedProviders>
|
<SharedProviders>{children}</SharedProviders>
|
||||||
</ShakeReportProvider>
|
// </ShakeReportProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user