mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
added mpv switch toggle
This commit is contained in:
parent
30ebba0722
commit
7a439fa814
5 changed files with 77 additions and 9 deletions
|
|
@ -1,6 +1,23 @@
|
|||
#import <React/RCTViewManager.h>
|
||||
// Dummy
|
||||
@interface KSPlayerManager : NSObject
|
||||
#import <AVKit/AVRoutePickerView.h>
|
||||
|
||||
@interface AirPlayRoutePickerViewManager : RCTViewManager
|
||||
@end
|
||||
@implementation KSPlayerManager
|
||||
|
||||
@implementation AirPlayRoutePickerViewManager
|
||||
|
||||
// Expose as `AirPlayRoutePickerView` for `requireNativeComponent`
|
||||
RCT_EXPORT_MODULE(AirPlayRoutePickerView)
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
AVRoutePickerView *picker = [AVRoutePickerView new];
|
||||
picker.backgroundColor = UIColor.clearColor;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
picker.tintColor = UIColor.whiteColor;
|
||||
picker.activeTintColor = UIColor.whiteColor;
|
||||
}
|
||||
return picker;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
||||
import { View, StatusBar, StyleSheet, Animated, Dimensions, Platform } from 'react-native';
|
||||
import { View, StatusBar, StyleSheet, Animated, Dimensions, Platform, Alert } from 'react-native';
|
||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import axios from 'axios';
|
||||
|
|
@ -502,6 +502,13 @@ const KSPlayerCore: React.FC = () => {
|
|||
modals.setShowErrorModal(true);
|
||||
};
|
||||
|
||||
// Confirm and execute the switch to MPV (iOS manual switch)
|
||||
const confirmSwitchToMPV = useCallback(() => {
|
||||
lastPlaybackTimeRef.current = currentTime || lastPlaybackTimeRef.current || 0;
|
||||
hasAviOSFailed.current = true; // reuse the resume-on-load path
|
||||
setUseMpvFallback(true);
|
||||
}, [currentTime]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
if (isSyncingBeforeClose.current) return;
|
||||
isSyncingBeforeClose.current = true;
|
||||
|
|
@ -816,10 +823,23 @@ const KSPlayerCore: React.FC = () => {
|
|||
onSwitchToMPV={
|
||||
(!shouldUseMpvOnly && !useMpvFallback)
|
||||
? () => {
|
||||
// Manual switch (like Android): go to MPV for this session and resume at current time.
|
||||
lastPlaybackTimeRef.current = currentTime || lastPlaybackTimeRef.current || 0;
|
||||
hasAviOSFailed.current = true; // reuse the resume-on-load path
|
||||
setUseMpvFallback(true);
|
||||
// Manual switch should confirm (like Android)
|
||||
Alert.alert(
|
||||
'Switch to MPV Player?',
|
||||
'This will switch from AVPlayer to MPV player. Use this if you\'re facing playback issues. The switch cannot be undone during this playback session.',
|
||||
[
|
||||
{
|
||||
text: 'Cancel',
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Switch to MPV',
|
||||
onPress: confirmSwitchToMPV,
|
||||
style: 'default',
|
||||
},
|
||||
],
|
||||
{ cancelable: true }
|
||||
);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
|
|
@ -1028,6 +1048,7 @@ const KSPlayerCore: React.FC = () => {
|
|||
onSelectStream={handleEpisodeStreamSelect}
|
||||
metadata={{ id: id, name: title }}
|
||||
/>
|
||||
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|||
import { styles } from '../utils/playerStyles'; // Updated styles
|
||||
import { getTrackDisplayName } from '../utils/playerUtils';
|
||||
import { useTheme } from '../../../contexts/ThemeContext';
|
||||
import AirPlayRoutePicker from '../ios/components/AirPlayRoutePicker';
|
||||
|
||||
interface PlayerControlsProps {
|
||||
showControls: boolean;
|
||||
|
|
@ -350,8 +351,10 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
|
|||
(Platform.OS === 'ios' && onSwitchToMPV && playerBackend === 'AVPlayer')
|
||||
) && (
|
||||
<TouchableOpacity
|
||||
style={{ padding: 8 }}
|
||||
style={[styles.topButton, { zIndex: 2 }]}
|
||||
onPress={onSwitchToMPV}
|
||||
hitSlop={{ top: 10, left: 10, right: 10, bottom: 10 }}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Ionicons
|
||||
name="swap-horizontal"
|
||||
|
|
@ -360,6 +363,13 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
|
|||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* AirPlay picker (iOS + AVPlayer) */}
|
||||
{Platform.OS === 'ios' && playerBackend === 'AVPlayer' && (
|
||||
<View style={{ width: closeIconSize + 16, height: closeIconSize + 16, zIndex: 1 }}>
|
||||
<AirPlayRoutePicker style={{ width: '100%', height: '100%' }} />
|
||||
</View>
|
||||
)}
|
||||
<TouchableOpacity style={styles.closeButton} onPress={handleClose}>
|
||||
<Ionicons name="close" size={closeIconSize} color="white" />
|
||||
</TouchableOpacity>
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ export const AVPlayerSurface: React.FC<AVPlayerSurfaceProps> = ({
|
|||
volume={volume}
|
||||
rate={playbackSpeed}
|
||||
resizeMode={resizeMode as any}
|
||||
allowsExternalPlayback={true}
|
||||
selectedAudioTrack={selectedAudioTrack}
|
||||
selectedTextTrack={selectedTextTrack}
|
||||
onLoad={handleLoad}
|
||||
|
|
|
|||
19
src/components/player/ios/components/AirPlayRoutePicker.tsx
Normal file
19
src/components/player/ios/components/AirPlayRoutePicker.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import React from 'react';
|
||||
import { Platform, requireNativeComponent, ViewStyle, View } from 'react-native';
|
||||
|
||||
type Props = {
|
||||
style?: ViewStyle;
|
||||
};
|
||||
|
||||
const NativeAirPlayRoutePickerView =
|
||||
Platform.OS === 'ios'
|
||||
? requireNativeComponent<Props>('AirPlayRoutePickerView')
|
||||
: null;
|
||||
|
||||
export const AirPlayRoutePicker: React.FC<Props> = (props) => {
|
||||
if (!NativeAirPlayRoutePickerView) return <View style={props.style} />;
|
||||
return <NativeAirPlayRoutePickerView {...props} />;
|
||||
};
|
||||
|
||||
export default AirPlayRoutePicker;
|
||||
|
||||
Loading…
Reference in a new issue