mirror of
https://github.com/jellyfin/jellyfin-expo.git
synced 2024-11-27 00:00:26 +00:00
195 lines
6.2 KiB
JavaScript
195 lines
6.2 KiB
JavaScript
/**
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
import compareVersions from 'compare-versions';
|
|
import Constants from 'expo-constants';
|
|
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
|
import { action } from 'mobx';
|
|
import { observer } from 'mobx-react-lite';
|
|
import React, { useState } from 'react';
|
|
import { BackHandler, Platform } from 'react-native';
|
|
|
|
import MediaTypes from '../constants/MediaTypes';
|
|
import { useStores } from '../hooks/useStores';
|
|
import DownloadModel from '../models/DownloadModel';
|
|
import { getAppName, getDeviceProfile, getSafeDeviceName } from '../utils/Device';
|
|
import StaticScriptLoader from '../utils/StaticScriptLoader';
|
|
import { openBrowser } from '../utils/WebBrowser';
|
|
|
|
import RefreshWebView from './RefreshWebView';
|
|
|
|
const NativeShellWebView = observer(
|
|
function NativeShellWebView(props, ref) {
|
|
const { rootStore } = useStores();
|
|
const [ isRefreshing, setIsRefreshing ] = useState(false);
|
|
|
|
const server = rootStore.serverStore.servers[rootStore.settingStore.activeServer];
|
|
const isPluginSupported = !!server.info?.Version && compareVersions.compare(server.info.Version, '10.7', '>=');
|
|
|
|
const injectedJavaScript = `
|
|
window.ExpoAppInfo = {
|
|
appName: '${getAppName()}',
|
|
appVersion: '${Constants.nativeAppVersion}',
|
|
deviceId: '${rootStore.deviceId}',
|
|
deviceName: '${getSafeDeviceName().replace(/'/g, '\\\'')}'
|
|
};
|
|
|
|
window.ExpoAppSettings = {
|
|
isPluginSupported: ${isPluginSupported},
|
|
isNativeVideoPlayerEnabled: ${rootStore.settingStore.isNativeVideoPlayerEnabled},
|
|
isExperimentalNativeAudioPlayerEnabled: ${rootStore.settingStore.isExperimentalNativeAudioPlayerEnabled},
|
|
isExperimentalDownloadsEnabled: ${rootStore.settingStore.isExperimentalDownloadsEnabled}
|
|
};
|
|
|
|
window.ExpoVideoProfile = ${JSON.stringify(getDeviceProfile({ enableFmp4: rootStore.settingStore.isFmp4Enabled }))};
|
|
|
|
function postExpoEvent(event, data) {
|
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
event: event,
|
|
data: data
|
|
}));
|
|
}
|
|
|
|
${StaticScriptLoader.scripts.NativeAudioPlayer}
|
|
${StaticScriptLoader.scripts.NativeVideoPlayer}
|
|
|
|
${StaticScriptLoader.scripts.NativeShell}
|
|
|
|
${StaticScriptLoader.scripts.ExpoRouterShim}
|
|
|
|
window.onerror = console.error;
|
|
|
|
true;
|
|
`;
|
|
|
|
const onRefresh = () => {
|
|
// Disable pull to refresh when in fullscreen
|
|
if (rootStore.isFullscreen) return;
|
|
|
|
// Stop media playback in native players
|
|
rootStore.mediaStore.shouldStop = true;
|
|
|
|
setIsRefreshing(true);
|
|
ref.current?.reload();
|
|
setIsRefreshing(false);
|
|
};
|
|
|
|
const onMessage = action(({ nativeEvent: state }) => {
|
|
try {
|
|
const { event, data } = JSON.parse(state.data);
|
|
switch (event) {
|
|
case 'AppHost.exit':
|
|
BackHandler.exitApp();
|
|
break;
|
|
case 'enableFullscreen':
|
|
rootStore.isFullscreen = true;
|
|
break;
|
|
case 'disableFullscreen':
|
|
rootStore.isFullscreen = false;
|
|
break;
|
|
case 'downloadFile':
|
|
console.log('Download item', data);
|
|
/* eslint-disable no-case-declarations */
|
|
const url = new URL(data.item.url);
|
|
const apiKey = url.searchParams.get('api_key');
|
|
/* eslint-enable no-case-declarations */
|
|
rootStore.downloadStore.add(new DownloadModel(
|
|
data.item.itemId,
|
|
data.item.serverId,
|
|
server.urlString,
|
|
apiKey,
|
|
data.item.title,
|
|
data.item.filename,
|
|
data.item.url
|
|
));
|
|
break;
|
|
case 'openUrl':
|
|
console.log('Opening browser for external url', data.url);
|
|
openBrowser(data.url);
|
|
break;
|
|
case 'updateMediaSession':
|
|
// Keep the screen awake when music is playing
|
|
if (rootStore.settingStore.isScreenLockEnabled) {
|
|
activateKeepAwake();
|
|
}
|
|
break;
|
|
case 'hideMediaSession':
|
|
// When music session stops disable keep awake
|
|
if (rootStore.settingStore.isScreenLockEnabled) {
|
|
deactivateKeepAwake();
|
|
}
|
|
break;
|
|
case 'ExpoAudioPlayer.play':
|
|
case 'ExpoVideoPlayer.play':
|
|
rootStore.mediaStore.type = event === 'ExpoAudioPlayer.play' ? MediaTypes.Audio : MediaTypes.Video;
|
|
rootStore.mediaStore.uri = data.url;
|
|
rootStore.mediaStore.backdropUri = data.backdropUrl;
|
|
rootStore.mediaStore.isFinished = false;
|
|
rootStore.mediaStore.positionTicks = data.playerStartPositionTicks;
|
|
break;
|
|
case 'ExpoAudioPlayer.playPause':
|
|
case 'ExpoVideoPlayer.playPause':
|
|
rootStore.mediaStore.shouldPlayPause = true;
|
|
break;
|
|
case 'ExpoAudioPlayer.stop':
|
|
case 'ExpoVideoPlayer.stop':
|
|
rootStore.mediaStore.shouldStop = true;
|
|
break;
|
|
case 'console.debug':
|
|
// console.debug('[Browser Console]', data);
|
|
break;
|
|
case 'console.error':
|
|
console.error('[Browser Console]', data);
|
|
break;
|
|
case 'console.info':
|
|
// console.info('[Browser Console]', data);
|
|
break;
|
|
case 'console.log':
|
|
// console.log('[Browser Console]', data);
|
|
break;
|
|
case 'console.warn':
|
|
console.warn('[Browser Console]', data);
|
|
break;
|
|
default:
|
|
console.debug('[HomeScreen.onMessage]', event, data);
|
|
}
|
|
} catch (ex) {
|
|
console.warn('Exception handling message', state.data);
|
|
}
|
|
});
|
|
|
|
return (
|
|
<RefreshWebView
|
|
ref={ref}
|
|
// Allow any origin blocking can break various things like book playback
|
|
originWhitelist={[ '*' ]}
|
|
source={{ uri: server.urlString }}
|
|
// Inject javascript for NativeShell
|
|
// This method is preferred, but only supported on iOS currently
|
|
injectedJavaScriptBeforeContentLoaded={Platform.OS === 'ios' ? injectedJavaScript : null}
|
|
// Fallback for non-iOS
|
|
injectedJavaScript={Platform.OS !== 'ios' ? injectedJavaScript : null}
|
|
onMessage={onMessage}
|
|
isRefreshing={isRefreshing}
|
|
onRefresh={onRefresh}
|
|
// Pass through additional props
|
|
{...props}
|
|
// Make scrolling feel faster
|
|
decelerationRate='normal'
|
|
// Media playback options to fix video player
|
|
allowsInlineMediaPlayback={true}
|
|
mediaPlaybackRequiresUserAction={false}
|
|
// Use WKWebView on iOS
|
|
useWebKit={true}
|
|
showsVerticalScrollIndicator={false}
|
|
showsHorizontalScrollIndicator={false}
|
|
/>
|
|
);
|
|
}, { forwardRef: true }
|
|
);
|
|
|
|
export default NativeShellWebView;
|