@interactify-live/pindo-wizard-react-native
Version:
React Native PindoWizard component for media capture and interaction management
317 lines (316 loc) • 17.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const react_native_1 = require("react-native");
const react_native_image_picker_1 = require("react-native-image-picker");
const react_native_vision_camera_1 = require("react-native-vision-camera");
const Gallery_1 = __importDefault(require("./icons/Gallery"));
const Rotate_1 = __importDefault(require("./icons/Rotate"));
const CaptureButton_1 = __importDefault(require("./CaptureButton"));
const CameraComponent = ({ onCapture, onGallerySelect, onClose: _onClose, settings: _settings = {
isVideoActive: false,
isInteractionActive: false,
isCoverActive: false,
numMedias: 1,
flashEnabled: false,
}, }) => {
const [isRecording, setIsRecording] = (0, react_1.useState)(false);
const [cameraType, setCameraType] = (0, react_1.useState)("back");
const [mode, setMode] = (0, react_1.useState)(_settings.isVideoActive ? "photo" : "photo");
const captureButtonRef = (0, react_1.useRef)(null);
const cameraRef = (0, react_1.useRef)(null);
// Use VisionCamera's built-in permission hooks
const { hasPermission: hasCameraPermission, requestPermission: requestCameraPermission, } = (0, react_native_vision_camera_1.useCameraPermission)();
const { hasPermission: hasMicrophonePermission, requestPermission: requestMicrophonePermission, } = (0, react_native_vision_camera_1.useMicrophonePermission)();
// Get camera device based on type
const device = (0, react_native_vision_camera_1.useCameraDevice)(cameraType);
// Combined permission state
const hasAllPermissions = hasCameraPermission && (mode === "photo" || hasMicrophonePermission);
(0, react_1.useEffect)(() => {
const requestPermissions = async () => {
if (!hasCameraPermission) {
await requestCameraPermission();
}
if (mode === "video" && !hasMicrophonePermission) {
await requestMicrophonePermission();
}
};
requestPermissions();
}, [
hasCameraPermission,
hasMicrophonePermission,
mode,
requestCameraPermission,
requestMicrophonePermission,
]);
// Ensure mode is 'photo' when video is not active
(0, react_1.useEffect)(() => {
if (!_settings.isVideoActive && mode !== "photo") {
setMode("photo");
}
}, [_settings.isVideoActive, mode]);
const handleCapture = async () => {
if (!cameraRef.current || !device) {
react_native_1.Alert.alert("Error", "Camera is not available.");
return;
}
if (!hasAllPermissions) {
react_native_1.Alert.alert("Permission Required", mode === "video"
? "Both camera and microphone permissions are required to record video."
: "Camera permission is required to take photos.");
return;
}
try {
if (mode === "video") {
// Video mode
if (isRecording) {
// Stop recording
setIsRecording(false);
captureButtonRef.current?.stop();
await cameraRef.current.stopRecording();
}
else {
// Start recording
setIsRecording(true);
captureButtonRef.current?.start(5000); // 5 seconds animation
await cameraRef.current.startRecording({
onRecordingFinished: (video) => {
onCapture(`file://${video.path}`, "video");
},
onRecordingError: (error) => {
console.error("Recording error:", error);
react_native_1.Alert.alert("Error", "Failed to record video");
},
});
}
}
else {
// Photo mode
const photo = await cameraRef.current.takePhoto();
onCapture(`file://${photo.path}`, "photo");
}
}
catch (error) {
console.error("Camera capture error:", error);
react_native_1.Alert.alert("Error", "Failed to capture media");
setIsRecording(false);
captureButtonRef.current?.stop();
}
};
const handleGalleryPress = async () => {
const options = {
mediaType: "mixed",
quality: 1,
includeBase64: false,
};
try {
const response = await (0, react_native_image_picker_1.launchImageLibrary)(options);
if (response.didCancel) {
return;
}
if (response.errorCode) {
react_native_1.Alert.alert("Error", `Gallery error: ${response.errorMessage}`);
return;
}
if (response.assets && response.assets.length > 0) {
const asset = response.assets[0];
if (asset.uri) {
const type = asset.type?.startsWith("video") ? "video" : "photo";
onGallerySelect(asset.uri, type);
}
}
}
catch (error) {
console.error("Gallery error:", error);
react_native_1.Alert.alert("Error", "Failed to pick media from gallery");
}
};
const toggleCamera = () => {
setCameraType((prev) => (prev === "back" ? "front" : "back"));
};
if (!hasAllPermissions) {
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [_settings.isVideoActive && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.topControls, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.modeToggleContainer, children: [(0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [
styles.modeButton,
mode === "video" && styles.modeButtonActive,
], onPress: () => setMode("video"), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [
styles.modeButtonText,
mode === "video" && styles.modeButtonTextActive,
], children: "\u0648\u06CC\u062F\u0626\u0648" }) }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [
styles.modeButton,
mode === "photo" && styles.modeButtonActive,
], onPress: () => setMode("photo"), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [
styles.modeButtonText,
mode === "photo" && styles.modeButtonTextActive,
], children: "\u0639\u06A9\u0633" }) })] }) })), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.permissionContainer, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.permissionText, children: "No access to camera" }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: styles.permissionButton, onPress: async () => {
if (!hasCameraPermission) {
await requestCameraPermission();
}
if (mode === "video" && !hasMicrophonePermission) {
await requestMicrophonePermission();
}
}, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.permissionButtonText, children: "Grant Permissions" }) })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.bottomControls, children: [(0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.galleryButton, onPress: handleGalleryPress, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.galleryIcon, children: (0, jsx_runtime_1.jsx)(Gallery_1.default, { width: 24, height: 24, fill: "#ffffff" }) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.galleryText, children: "\u06AF\u0627\u0644\u0631\u06CC" })] }), (0, jsx_runtime_1.jsx)(CaptureButton_1.default, { ref: captureButtonRef, onPress: handleCapture, captureType: mode }), (0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.flipButton, onPress: toggleCamera, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.flipIcon, children: (0, jsx_runtime_1.jsx)(Rotate_1.default, { width: 24, height: 24, stroke: "#ffffff", strokeWidth: 1.5 }) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.flipText, children: "\u0628\u0686\u0631\u062E" })] })] })] }));
}
if (!device) {
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [_settings.isVideoActive && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.topControls, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.modeToggleContainer, children: [(0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [
styles.modeButton,
mode === "video" && styles.modeButtonActive,
], onPress: () => setMode("video"), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [
styles.modeButtonText,
mode === "video" && styles.modeButtonTextActive,
], children: "\u0648\u06CC\u062F\u0626\u0648" }) }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [
styles.modeButton,
mode === "photo" && styles.modeButtonActive,
], onPress: () => setMode("photo"), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [
styles.modeButtonText,
mode === "photo" && styles.modeButtonTextActive,
], children: "\u0639\u06A9\u0633" }) })] }) })), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.loadingContainer, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.loadingText, children: "Camera not available" }) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.bottomControls, children: [(0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.galleryButton, onPress: handleGalleryPress, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.galleryIcon, children: (0, jsx_runtime_1.jsx)(Gallery_1.default, { width: 24, height: 24, fill: "#ffffff" }) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.galleryText, children: "\u06AF\u0627\u0644\u0631\u06CC" })] }), (0, jsx_runtime_1.jsx)(CaptureButton_1.default, { ref: captureButtonRef, onPress: handleCapture, captureType: mode }), (0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.flipButton, onPress: toggleCamera, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.flipIcon, children: (0, jsx_runtime_1.jsx)(Rotate_1.default, { width: 24, height: 24, stroke: "#ffffff", strokeWidth: 1.5 }) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.flipText, children: "\u0628\u0686\u0631\u062E" })] })] })] }));
}
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [_settings.isVideoActive && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.topControls, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.modeToggleContainer, children: [(0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [
styles.modeButton,
mode === "video" && styles.modeButtonActive,
], onPress: () => setMode("video"), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [
styles.modeButtonText,
mode === "video" && styles.modeButtonTextActive,
], children: "\u0648\u06CC\u062F\u0626\u0648" }) }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [
styles.modeButton,
mode === "photo" && styles.modeButtonActive,
], onPress: () => setMode("photo"), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [
styles.modeButtonText,
mode === "photo" && styles.modeButtonTextActive,
], children: "\u0639\u06A9\u0633" }) })] }) })), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.cameraPreview, children: (0, jsx_runtime_1.jsx)(react_native_vision_camera_1.Camera, { ref: cameraRef, style: styles.camera, device: device, isActive: true, photo: true, video: true, audio: mode === "video" }) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.bottomControls, children: [(0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.galleryButton, onPress: handleGalleryPress, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.galleryIcon, children: (0, jsx_runtime_1.jsx)(Gallery_1.default, { width: 24, height: 24, fill: "#ffffff" }) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.galleryText, children: "\u06AF\u0627\u0644\u0631\u06CC" })] }), (0, jsx_runtime_1.jsx)(CaptureButton_1.default, { ref: captureButtonRef, onPress: handleCapture, captureType: mode }), (0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.flipButton, onPress: toggleCamera, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.flipIcon, children: (0, jsx_runtime_1.jsx)(Rotate_1.default, { width: 24, height: 24, stroke: "#ffffff", strokeWidth: 1.5 }) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.flipText, children: "\u0628\u0686\u0631\u062E" })] })] })] }));
};
const styles = react_native_1.StyleSheet.create({
container: {
flex: 1,
backgroundColor: "rgb(38, 38, 38)",
flexDirection: "column",
},
topControls: {
height: 100,
paddingTop: react_native_1.Platform.OS === "ios" ? 50 : 20,
paddingBottom: 20,
backgroundColor: "rgb(38, 38, 38)",
alignItems: "center",
zIndex: 10,
},
modeToggleContainer: {
flexDirection: "row",
backgroundColor: "rgb(38, 38, 38)",
borderRadius: 8,
borderColor: "rgb(141, 143, 144)",
borderWidth: 1,
padding: 5,
minWidth: 200,
},
modeButton: {
flex: 1,
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 21,
alignItems: "center",
justifyContent: "center",
},
modeButtonActive: {
backgroundColor: "#ffffff",
},
modeButtonText: {
color: "#ffffff",
fontSize: 16,
fontWeight: "600",
},
modeButtonTextActive: {
color: "#2a2a2a",
},
cameraPreview: {
flex: 1,
backgroundColor: "#1a1a1a",
margin: 10,
},
camera: {
flex: 1,
width: "100%",
},
bottomControls: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 20,
paddingBottom: 40,
backgroundColor: "rgba(0, 0, 0, 0.8)",
paddingTop: 20,
},
galleryButton: {
alignItems: "center",
minWidth: 60,
},
galleryIcon: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "rgba(255, 255, 255, 0.2)",
justifyContent: "center",
alignItems: "center",
marginBottom: 4,
},
galleryText: {
color: "#ffffff",
fontSize: 12,
textAlign: "center",
},
flipButton: {
alignItems: "center",
minWidth: 60,
},
flipIcon: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "rgba(255, 255, 255, 0.2)",
justifyContent: "center",
alignItems: "center",
marginBottom: 4,
},
flipText: {
color: "#ffffff",
fontSize: 12,
textAlign: "center",
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
loadingText: {
color: "#ffffff",
fontSize: 16,
},
permissionContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
},
permissionText: {
color: "#ffffff",
fontSize: 18,
marginBottom: 20,
textAlign: "center",
},
permissionButton: {
backgroundColor: "#007AFF",
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 8,
marginBottom: 10,
},
permissionButtonText: {
color: "#ffffff",
fontSize: 16,
fontWeight: "600",
},
});
exports.default = CameraComponent;