// @ts-ignore - Peer dependency import { View, Text, Pressable, FlatList, Image } from 'react-native'; import React, { useRef, useCallback } from 'react'; // @ts-ignore - Peer dependency import { ScaledSheet } from 'react-native-size-matters'; // @ts-ignore - Peer dependency import LinearGradient from 'react-native-linear-gradient'; import { useEditorContext } from '../../context/EditorContext'; import { useEditorState } from '../../context/EditorStateContext'; import { useFontFamily } from '../../context/FontFamilyContext'; import type { EditorTool } from '../../context/EditorContext'; import { CAPTION_BG_COLORS, COLORS } from '../../constants/colors'; import { pick, keepLocalCopy, types, // @ts-ignore - Peer dependency } from '@react-native-documents/picker'; // @ts-ignore - Peer dependency import { MusicIcon, TextIcon, CropIcon, TrimIcon, MicOutline, DownloadIcon, // @ts-ignore - Peer dependency } from '../../assets/icons/index.js'; const TOOLS: { id: EditorTool; label: string; icon: any }[] = [ { id: 'bgm', label: 'Music', icon: MusicIcon }, { id: 'text', label: 'Text', icon: TextIcon }, { id: 'crop', label: 'Crop', icon: CropIcon }, { id: 'trim', label: 'Trim', icon: TrimIcon }, { id: 'voiceover', label: 'Voice', icon: MicOutline }, { id: 'save', label: 'Save', icon: DownloadIcon }, ]; type BottomToolBarProps = { onToolPress?: () => void; onExport?: () => void; }; type ToolItemProps = { tool: (typeof TOOLS)[0]; isEnabled: boolean; isSelected: boolean; onPress: (id: EditorTool) => void; fontStyle?: object | null; }; const ToolItem = React.memo( ({ tool, isEnabled, isSelected, onPress, fontStyle }: ToolItemProps) => { if (!isEnabled && tool.id !== 'save') return null; return ( onPress(tool.id)} style={[styles.toolCard, isSelected && styles.toolCardSelected]} > {tool.label} ); } ); export const BottomToolBar = React.memo( ({ onToolPress, onExport }: BottomToolBarProps) => { const { setActiveTool, enabledTools, activeTool } = useEditorContext(); const { fontStyle } = useFontFamily(); const { setAudioUri, setActiveSegment, setIsTextEditorVisible, setEditingTextElement, isPlaying, setIsPlaying, } = useEditorState(); const wasPlayingBeforePickerRef = useRef(false); const handleBGMPress = useCallback(async () => { try { // Store previous playing state before pausing wasPlayingBeforePickerRef.current = isPlaying; if (isPlaying) { setIsPlaying(false); } const [pickResult] = await pick({ type: [types.audio], allowMultiSelection: false, }); const selectedFile = [pickResult]?.[0]; if (selectedFile) { try { const [localCopy] = await keepLocalCopy({ files: [ { uri: selectedFile.uri, fileName: selectedFile.name ?? 'audio', }, ], destination: 'cachesDirectory', }); const audioUriToUse = localCopy?.localUri || localCopy?.uri || selectedFile.uri; if (audioUriToUse) { setAudioUri(audioUriToUse); setActiveTool('bgm'); return; } } catch (copyErr: any) { console.warn('Failed to create local copy:', copyErr); if (selectedFile.uri) { setAudioUri(selectedFile.uri); setActiveTool('bgm'); return; } } } if (wasPlayingBeforePickerRef.current) { setIsPlaying(true); } } catch (err: any) { // Handle cancellation manually as isCancel might be undefined const isCancelled = err?.code === 'DOCUMENT_PICKER_CANCELED' || err?.message === 'User canceled document picker'; if (isCancelled) { if (wasPlayingBeforePickerRef.current) { setIsPlaying(true); } } else { // console.error('Audio picker error:', err); if (wasPlayingBeforePickerRef.current) { setIsPlaying(true); } } } }, [isPlaying, setIsPlaying, setAudioUri, setActiveTool]); const handlePress = useCallback( (toolId: EditorTool) => { onToolPress?.(); if (toolId === 'bgm') { handleBGMPress(); } else if (toolId === 'text') { setEditingTextElement(null); setIsTextEditorVisible(true); if (isPlaying) setIsPlaying(false); setActiveTool('text'); } else if (toolId === 'save') { // Trigger export onExport?.(); } else { if (toolId === 'trim') { setActiveSegment({ type: 'trim' }); } setActiveTool(activeTool === toolId ? null : toolId); } }, [ onToolPress, handleBGMPress, setEditingTextElement, setIsTextEditorVisible, isPlaying, setIsPlaying, setActiveTool, setActiveSegment, activeTool, onExport, ] ); const renderToolItem = useCallback( ({ item: tool }: { item: (typeof TOOLS)[0] }) => { return ( ); }, [enabledTools, activeTool, handlePress, fontStyle] ); const keyExtractor = useCallback((item: any) => item.id, []); return ( ); } ); const styles = ScaledSheet.create({ container: { height: '100@ms', justifyContent: 'center', backgroundColor: 'transparent', }, toolsList: { paddingHorizontal: '12@ms', alignItems: 'center', }, toolCard: { alignItems: 'center', marginHorizontal: '4@ms', padding: '8@ms', minWidth: '70@ms', }, toolCardSelected: { backgroundColor: CAPTION_BG_COLORS[2], borderWidth: 1, borderColor: 'white', borderRadius: '12@ms', }, toolIconContainer: { width: '48@ms', height: '48@ms', borderRadius: '24@ms', justifyContent: 'center', alignItems: 'center', marginBottom: '8@ms', }, toolIconText: { width: '24@ms', height: '24@ms', resizeMode: 'contain', }, toolLabel: { color: '#fff', fontSize: '11@ms', textAlign: 'center', fontWeight: '600', textShadowColor: 'rgba(0,0,0,0.5)', textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 1, }, });