@8man/react-native-media-console
Version:
A media player for the react-native-video component
443 lines (432 loc) • 15.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _reactNative = require("react-native");
var _react = _interopRequireWildcard(require("react"));
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
var _MaterialIcons = _interopRequireDefault(require("@expo/vector-icons/MaterialIcons"));
var _reactNativeSystemSetting = _interopRequireDefault(require("react-native-system-setting"));
var _reactNativeGestureHandler = require("react-native-gesture-handler");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
//@ts-ignore
const SWIPE_RANGE = 370;
const Ripple = ({
visible,
isLeft,
totalTime,
showControls
}) => {
const {
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT
} = _reactNative.Dimensions.get('window');
const scale = (0, _reactNativeReanimated.useSharedValue)(0);
const opacity = (0, _reactNativeReanimated.useSharedValue)(0);
_react.default.useEffect(() => {
if (visible) {
scale.value = (0, _reactNativeReanimated.withSequence)((0, _reactNativeReanimated.withTiming)(1.5, {
duration: 400
}), (0, _reactNativeReanimated.withDelay)(400, (0, _reactNativeReanimated.withTiming)(0, {
duration: 400
})));
opacity.value = (0, _reactNativeReanimated.withSequence)((0, _reactNativeReanimated.withTiming)(0.4, {
duration: 400
}), (0, _reactNativeReanimated.withDelay)(400, (0, _reactNativeReanimated.withTiming)(0, {
duration: 400
})));
}
}, [visible]);
const rippleStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
opacity: opacity.value,
//@ts-ignore
transform: [{
scale: scale.value
}]
}));
return visible ? /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: {
position: 'absolute',
top: showControls ? -70 : -45,
left: isLeft ? '-10%' : undefined,
right: isLeft ? undefined : '-10%',
width: SCREEN_WIDTH / 2.5,
height: SCREEN_HEIGHT,
zIndex: 999
}
}, /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
style: [{
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: 'rgba(0,0,0,0.9)',
justifyContent: 'center',
alignItems: 'center',
borderRadius: SCREEN_HEIGHT / 2
}, rippleStyle]
}, /*#__PURE__*/_react.default.createElement(_MaterialIcons.default, {
name: isLeft ? 'fast-rewind' : 'fast-forward',
size: 28,
color: "white"
}), !isNaN(totalTime) && totalTime > 0 && /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
style: {
color: 'white',
marginTop: 8,
fontSize: 12
}
}, Math.floor(totalTime), "s"))) : null;
};
const Gestures = ({
forward,
rewind,
togglePlayPause,
toggleControls,
doubleTapTime,
tapActionTimeout,
tapAnywhereToPause,
rewindTime = 10,
showControls,
disableGesture
}) => {
const [rippleVisible, setRippleVisible] = (0, _react.useState)(false);
// const [ripplePosition,setRipplePosition] = useState({x: 0, y: 0});
const [isLeftRipple, setIsLeftRipple] = (0, _react.useState)(false);
const [totalSkipTime, setTotalSkipTime] = (0, _react.useState)(0);
const initialTapPosition = (0, _react.useRef)({
x: 0,
y: 0
});
const isDoubleTapRef = (0, _react.useRef)(false);
const currentSideRef = (0, _react.useRef)(null);
const tapCountRef = (0, _react.useRef)(0);
const skipTimeoutRef = (0, _react.useRef)(null);
const lastTapTimeRef = (0, _react.useRef)(0);
const {
width: SCREEN_WIDTH
} = _reactNative.Dimensions.get('window');
const resetState = () => {
isDoubleTapRef.current = false;
currentSideRef.current = null;
tapCountRef.current = 0;
lastTapTimeRef.current = 0;
setTotalSkipTime(0);
setRippleVisible(false);
if (skipTimeoutRef.current) {
clearTimeout(skipTimeoutRef.current);
skipTimeoutRef.current = null;
}
};
const handleSkip = async () => {
try {
const count = Number(tapCountRef.current) - 1;
const baseTime = Number(rewindTime);
const skipTime = baseTime * count;
console.log('Skip calculation:', {
count,
baseTime,
skipTime,
side: currentSideRef.current,
isValidNumber: !isNaN(skipTime) && skipTime > 0
});
if (!isNaN(skipTime) && skipTime > 0) {
if (currentSideRef.current === 'left') {
rewind(skipTime);
} else if (currentSideRef.current === 'right') {
forward(skipTime);
}
}
} catch (error) {
console.error('Error while skipping:', error);
} finally {
resetState();
}
};
const handleTap = (e, side) => {
const now = Date.now();
const touchX = e.nativeEvent.locationX;
const touchY = e.nativeEvent.locationY;
console.log('Tap details:', {
touchX,
side,
isDoubleTap: isDoubleTapRef.current,
timeSinceLastTap: now - lastTapTimeRef.current
});
if (now - lastTapTimeRef.current > 500) {
resetState();
}
if (!isDoubleTapRef.current) {
isDoubleTapRef.current = true;
initialTapPosition.current = {
x: touchX,
y: touchY
};
currentSideRef.current = side;
tapCountRef.current = 1;
lastTapTimeRef.current = now;
tapActionTimeout.current = setTimeout(() => {
if (tapAnywhereToPause) {
togglePlayPause();
} else {
toggleControls();
}
resetState();
}, doubleTapTime);
} else {
if (tapActionTimeout.current) {
clearTimeout(tapActionTimeout.current);
tapActionTimeout.current = null;
}
if (currentSideRef.current === side) {
tapCountRef.current += 1;
lastTapTimeRef.current = now;
const count = Number(tapCountRef.current) - 1;
const baseTime = Number(rewindTime);
const newSkipTime = baseTime * count;
console.log('Multiple tap calculation:', {
count,
baseTime,
newSkipTime,
tapCount: tapCountRef.current,
side
});
setTotalSkipTime(newSkipTime);
setRippleVisible(true);
// setRipplePosition(initialTapPosition.current);
setIsLeftRipple(side === 'left');
if (skipTimeoutRef.current) {
clearTimeout(skipTimeoutRef.current);
}
skipTimeoutRef.current = setTimeout(handleSkip, 500);
} else {
resetState();
isDoubleTapRef.current = true;
initialTapPosition.current = {
x: touchX,
y: touchY
};
currentSideRef.current = side;
tapCountRef.current = 1;
lastTapTimeRef.current = now;
tapActionTimeout.current = setTimeout(() => {
resetState();
}, doubleTapTime);
}
}
};
_react.default.useEffect(() => {
return () => {
if (skipTimeoutRef.current) {
clearTimeout(skipTimeoutRef.current);
}
if (tapActionTimeout.current) {
clearTimeout(tapActionTimeout.current);
}
};
}, []);
const volumeValue = (0, _reactNativeReanimated.useSharedValue)(0);
const brightnessValue = (0, _reactNativeReanimated.useSharedValue)(0);
const startVolume = (0, _reactNativeReanimated.useSharedValue)(0);
const startBrightness = (0, _reactNativeReanimated.useSharedValue)(0);
const [displayVolume, setDisplayVolume] = (0, _react.useState)(0);
const [displayBrightness, setDisplayBrightness] = (0, _react.useState)(0);
const [isVolumeVisible, setIsVolumeVisible] = (0, _react.useState)(false);
const [isBrightnessVisible, setIsBrightnessVisible] = (0, _react.useState)(false);
// Store original values in refs to maintain latest values for cleanup
const originalSettings = (0, _react.useRef)({
volume: 0,
brightness: 0
});
_react.default.useEffect(() => {
const initializeSettings = async () => {
try {
const currentVolume = await _reactNativeSystemSetting.default.getVolume();
const currentBrightness = await _reactNativeSystemSetting.default.getBrightness();
volumeValue.value = currentVolume;
brightnessValue.value = currentBrightness;
setDisplayVolume(currentVolume);
setDisplayBrightness(currentBrightness);
} catch (error) {
console.error('Error initializing settings:', error);
}
};
initializeSettings();
}, []);
const updateSystemVolume = _react.default.useCallback(newVolume => {
const clampedVolume = Math.max(0, Math.min(1, newVolume));
_reactNativeSystemSetting.default.setVolume(clampedVolume);
setDisplayVolume(clampedVolume);
}, []);
const updateSystemBrightness = _react.default.useCallback(newBrightness => {
const clampedBrightness = Math.max(0, Math.min(1, newBrightness));
_reactNativeSystemSetting.default.setAppBrightness(clampedBrightness);
setDisplayBrightness(clampedBrightness);
}, []);
const panGesture = _reactNativeGestureHandler.Gesture.Pan().minDistance(10) // Minimum distance before gesture starts
.onStart(event => {
'worklet';
const isLeftSide = event.x < SCREEN_WIDTH / 2;
if (isLeftSide) {
startBrightness.value = brightnessValue.value;
(0, _reactNativeReanimated.runOnJS)(setIsBrightnessVisible)(true);
} else {
startVolume.value = volumeValue.value;
(0, _reactNativeReanimated.runOnJS)(setIsVolumeVisible)(true);
}
}).onUpdate(event => {
'worklet';
const isLeftSide = event.x < SCREEN_WIDTH / 2;
const change = -event.translationY / SWIPE_RANGE;
if (isLeftSide) {
// Brightness control
const newBrightness = Math.max(0, Math.min(1, startBrightness.value + change));
brightnessValue.value = newBrightness;
(0, _reactNativeReanimated.runOnJS)(updateSystemBrightness)(newBrightness);
} else {
// Volume control
const newVolume = Math.max(0, Math.min(1, startVolume.value + change));
volumeValue.value = newVolume;
(0, _reactNativeReanimated.runOnJS)(updateSystemVolume)(newVolume);
}
}).onFinalize(() => {
'worklet';
(0, _reactNativeReanimated.runOnJS)(setIsVolumeVisible)(false);
(0, _reactNativeReanimated.runOnJS)(setIsBrightnessVisible)(false);
});
const ControlOverlay = /*#__PURE__*/_react.default.memo(({
value,
isVisible,
isVolume
}) => {
if (!isVisible) return null;
return /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
// @ts-ignore
style: {
position: 'absolute',
top: '50%',
left: !isVolume ? undefined : '15%',
right: !isVolume ? '15%' : undefined,
transform: [{
translateX: 0
}, {
translateY: showControls ? -20 : 0
}],
backgroundColor: 'rgba(0, 0, 0, 0.6)',
borderRadius: 10,
minWidth: 50,
padding: 10,
alignItems: 'center',
zIndex: 1000
}
}, /*#__PURE__*/_react.default.createElement(_MaterialIcons.default, {
name: isVolume ? value === 0 ? 'volume-mute' : value < 0.3 ? 'volume-down' : 'volume-up' : 'brightness-6',
size: 24,
color: "white"
}), /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
style: {
color: 'white',
marginTop: 5
}
}, Math.round(value * 100)));
});
// Initialize and store original settings
(0, _react.useEffect)(() => {
let mounted = true;
const initializeSettings = async () => {
try {
const [currentVolume, currentBrightness] = await Promise.all([_reactNativeSystemSetting.default.getVolume(), _reactNativeSystemSetting.default.getBrightness()]);
if (mounted) {
// Store original values
originalSettings.current = {
volume: currentVolume,
brightness: currentBrightness
};
// Set initial values
volumeValue.value = currentVolume;
brightnessValue.value = currentBrightness;
setDisplayVolume(currentVolume);
setDisplayBrightness(currentBrightness);
console.log('Original settings stored:🔥', {
volume: currentVolume,
brightness: currentBrightness
});
}
} catch (error) {
console.error('Error initializing settings:', error);
}
};
initializeSettings();
// Cleanup function
return () => {
mounted = false;
const resetSettings = async () => {
try {
// console.log('Resetting to original settings:🔥', originalSettings.current);
await Promise.all([
// SystemSetting.setVolume(originalSettings.current.volume),
_reactNativeSystemSetting.default.setAppBrightness(originalSettings.current.brightness)]);
// console.log('Settings reset successfully');
} catch (error) {
console.error('Error resetting settings:', error);
}
};
resetSettings();
};
}, []);
if (disableGesture) {
return null;
}
return /*#__PURE__*/_react.default.createElement(_reactNativeGestureHandler.GestureHandlerRootView, {
style: {
width: '100%',
height: '70%'
}
}, /*#__PURE__*/_react.default.createElement(_reactNativeGestureHandler.GestureDetector, {
gesture: panGesture
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: {
position: 'relative',
width: '100%',
height: '100%',
flexDirection: 'row'
}
}, /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
onPress: e => handleTap(e, 'left'),
style: {
flex: 1,
top: 40,
height: '100%',
position: 'relative'
}
}, /*#__PURE__*/_react.default.createElement(Ripple, {
visible: rippleVisible && isLeftRipple,
showControls: showControls,
isLeft: true,
totalTime: totalSkipTime
})), /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
onPress: e => handleTap(e, 'right'),
style: {
top: 40,
flex: 1,
height: '100%',
position: 'relative'
}
}, /*#__PURE__*/_react.default.createElement(Ripple, {
visible: rippleVisible && !isLeftRipple,
showControls: showControls,
isLeft: false,
totalTime: totalSkipTime
})))), /*#__PURE__*/_react.default.createElement(ControlOverlay, {
value: displayVolume,
isVisible: isVolumeVisible,
isVolume: true
}), /*#__PURE__*/_react.default.createElement(ControlOverlay, {
value: displayBrightness,
isVisible: isBrightnessVisible,
isVolume: false
}));
};
var _default = exports.default = Gestures;
//# sourceMappingURL=Gestures.js.map