added aspect ratio indicator

This commit is contained in:
tapframe 2026-01-21 17:48:11 +05:30
parent b33fde8c9e
commit 154d568aa3
4 changed files with 147 additions and 39 deletions

View file

@ -704,9 +704,21 @@ const AndroidVideoPlayer: React.FC = () => {
}, []);
const cycleResizeMode = useCallback(() => {
if (playerState.resizeMode === 'contain') playerState.setResizeMode('cover');
else playerState.setResizeMode('contain');
}, [playerState.resizeMode]);
gestureControls.showResizeModeOverlayFn(() => {
switch (playerState.resizeMode) {
case 'contain':
playerState.setResizeMode('cover');
break;
case 'cover':
playerState.setResizeMode('stretch');
break;
case 'stretch':
default:
playerState.setResizeMode('contain');
break;
}
});
}, [playerState.resizeMode, gestureControls.showResizeModeOverlayFn]);
// Memoize selectedTextTrack to prevent unnecessary re-renders
const memoizedSelectedTextTrack = useMemo(() => {
@ -861,6 +873,8 @@ const AndroidVideoPlayer: React.FC = () => {
volume={volume}
brightness={brightness}
controlsTimeout={controlsTimeout}
resizeMode={playerState.resizeMode}
resizeMode={playerState.resizeMode}
/>
<PlayerControls

View file

@ -1,5 +1,5 @@
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { View, Text, StyleSheet, Animated } from 'react-native';
import {
TapGestureHandler,
PanGestureHandler,
@ -21,6 +21,7 @@ interface GestureControlsProps {
volume: number;
brightness: number;
controlsTimeout: React.MutableRefObject<NodeJS.Timeout | null>;
resizeMode?: string;
}
export const GestureControls: React.FC<GestureControlsProps> = ({
@ -34,7 +35,8 @@ export const GestureControls: React.FC<GestureControlsProps> = ({
hideControls,
volume,
brightness,
controlsTimeout
controlsTimeout,
resizeMode = 'contain'
}) => {
const getVolumeIcon = (value: number) => {
@ -151,42 +153,77 @@ export const GestureControls: React.FC<GestureControlsProps> = ({
{/* Volume/Brightness Pill Overlay */}
{(gestureControls.showVolumeOverlay || gestureControls.showBrightnessOverlay) && (
<View style={localStyles.gestureIndicatorContainer}>
<View
style={[
localStyles.iconWrapper,
{
backgroundColor: gestureControls.showVolumeOverlay && volume === 0
? 'rgba(242, 184, 181)'
: 'rgba(59, 59, 59)'
}
]}
>
<MaterialIcons
name={
gestureControls.showVolumeOverlay
? getVolumeIcon(volume)
: getBrightnessIcon(brightness)
}
size={24}
color={
gestureControls.showVolumeOverlay && volume === 0
? 'rgba(96, 20, 16)'
: 'rgba(255, 255, 255)'
}
/>
</View>
<View style={localStyles.gestureIndicatorPill}>
<View
style={[
localStyles.iconWrapper,
{
backgroundColor: gestureControls.showVolumeOverlay && volume === 0
? 'rgba(242, 184, 181)'
: 'rgba(59, 59, 59)'
}
]}
>
<MaterialIcons
name={
gestureControls.showVolumeOverlay
? getVolumeIcon(volume)
: getBrightnessIcon(brightness)
}
size={24}
color={
gestureControls.showVolumeOverlay && volume === 0
? 'rgba(96, 20, 16)'
: 'rgba(255, 255, 255)'
}
/>
</View>
<Text
<Text
style={[
localStyles.gestureText,
gestureControls.showVolumeOverlay && volume === 0 && { color: 'rgba(242, 184, 181)' }
]}
>
{gestureControls.showVolumeOverlay && volume === 0
? "Muted"
: `${Math.round((gestureControls.showVolumeOverlay ? volume : brightness) * 100)}%`
}
</Text>
</View>
</View>
)}
{/* Aspect Ratio Overlay */}
{gestureControls.showResizeModeOverlay && (
<View style={localStyles.gestureIndicatorContainer}>
<Animated.View
style={[
localStyles.gestureText,
gestureControls.showVolumeOverlay && volume === 0 && { color: 'rgba(242, 184, 181)' }
localStyles.gestureIndicatorPill,
{ opacity: gestureControls.resizeModeOverlayOpacity }
]}
>
{gestureControls.showVolumeOverlay && volume === 0
? "Muted"
: `${Math.round((gestureControls.showVolumeOverlay ? volume : brightness) * 100)}%`
}
</Text>
<View
style={[
localStyles.iconWrapper,
{
backgroundColor: 'rgba(59, 59, 59)'
}
]}
>
<MaterialIcons
name="aspect-ratio"
size={24}
color="rgba(255, 255, 255)"
/>
</View>
<Text
style={localStyles.gestureText}
>
{resizeMode.charAt(0).toUpperCase() + resizeMode.slice(1)}
</Text>
</Animated.View>
</View>
)}
</>

View file

@ -1,5 +1,5 @@
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { View, Text, StyleSheet, Animated } from 'react-native';
import {
TapGestureHandler,
PanGestureHandler,
@ -21,6 +21,7 @@ interface GestureControlsProps {
volume: number;
brightness: number;
controlsTimeout: React.MutableRefObject<NodeJS.Timeout | null>;
resizeMode?: string;
}
export const GestureControls: React.FC<GestureControlsProps> = ({
@ -34,7 +35,8 @@ export const GestureControls: React.FC<GestureControlsProps> = ({
hideControls,
volume,
brightness,
controlsTimeout
controlsTimeout,
resizeMode = 'contain'
}) => {
const getVolumeIcon = (value: number) => {
@ -194,6 +196,29 @@ export const GestureControls: React.FC<GestureControlsProps> = ({
</View>
</View>
)}
{gestureControls.showResizeModeOverlay && (
<View style={localStyles.gestureIndicatorContainer}>
<Animated.View
style={[
localStyles.gestureIndicatorPill,
{ opacity: gestureControls.resizeModeOverlayOpacity }
]}
>
<View style={localStyles.iconWrapper}>
<MaterialIcons
name="aspect-ratio"
size={18}
color={'rgba(255, 255, 255, 0.9)'}
/>
</View>
<Text style={localStyles.gestureText}>
{resizeMode.charAt(0).toUpperCase() + resizeMode.slice(1)}
</Text>
</Animated.View>
</View>
)}
</>
);
};

View file

@ -19,18 +19,21 @@ export const usePlayerGestureControls = (config: GestureControlConfig) => {
// State for overlays
const [showVolumeOverlay, setShowVolumeOverlay] = useState(false);
const [showBrightnessOverlay, setShowBrightnessOverlay] = useState(false);
const [showResizeModeOverlay, setShowResizeModeOverlay] = useState(false);
// Animated values
const volumeGestureTranslateY = useRef(new Animated.Value(0)).current;
const brightnessGestureTranslateY = useRef(new Animated.Value(0)).current;
const volumeOverlayOpacity = useRef(new Animated.Value(0)).current;
const brightnessOverlayOpacity = useRef(new Animated.Value(0)).current;
const resizeModeOverlayOpacity = useRef(new Animated.Value(0)).current;
// Tracking refs
const lastVolumeGestureY = useRef(0);
const lastBrightnessGestureY = useRef(0);
const volumeOverlayTimeout = useRef<NodeJS.Timeout | null>(null);
const brightnessOverlayTimeout = useRef<NodeJS.Timeout | null>(null);
const resizeModeOverlayTimeout = useRef<NodeJS.Timeout | null>(null);
// Extract config with defaults and platform adjustments
const volumeRange = config.volumeRange || { min: 0, max: 1 };
@ -152,6 +155,30 @@ export const usePlayerGestureControls = (config: GestureControlConfig) => {
if (brightnessOverlayTimeout.current) {
clearTimeout(brightnessOverlayTimeout.current);
}
if (resizeModeOverlayTimeout.current) {
clearTimeout(resizeModeOverlayTimeout.current);
}
};
const showResizeModeOverlayFn = (callback?: () => void) => {
if (resizeModeOverlayTimeout.current) {
clearTimeout(resizeModeOverlayTimeout.current);
}
setShowResizeModeOverlay(true);
Animated.timing(resizeModeOverlayOpacity, {
toValue: 1,
duration: 100,
useNativeDriver: true,
}).start(() => {
if (callback) callback();
resizeModeOverlayTimeout.current = setTimeout(() => {
Animated.timing(resizeModeOverlayOpacity, {
toValue: 0,
duration: 200,
useNativeDriver: true,
}).start(() => setShowResizeModeOverlay(false));
}, overlayTimeout);
});
};
return {
@ -162,8 +189,13 @@ export const usePlayerGestureControls = (config: GestureControlConfig) => {
// Overlay state
showVolumeOverlay,
showBrightnessOverlay,
showResizeModeOverlay,
volumeOverlayOpacity,
brightnessOverlayOpacity,
resizeModeOverlayOpacity,
// Overlay functions
showResizeModeOverlayFn,
// Cleanup
cleanup,