fix(camera): matrix-based zoom for pinch/double-tap, tap-to-focus AE/AF lock, library letterbox smear fix, export raw JPEG bytes q95, resume isActive fixes, dark theme polish
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import React, { useState } from 'react';
|
||||
import { View, Text, TouchableOpacity, TextInput, Modal } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { Plus } from 'lucide-react-native';
|
||||
import * as Haptics from 'expo-haptics';
|
||||
|
||||
interface TopBarProps {
|
||||
mode: 'camera' | 'library';
|
||||
recipeName: string;
|
||||
onSaveRecipe: (name: string) => void;
|
||||
}
|
||||
|
||||
export default function TopBar({ mode, recipeName, onSaveRecipe }: TopBarProps) {
|
||||
const insets = useSafeAreaInsets();
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [newRecipeName, setNewRecipeName] = useState('');
|
||||
|
||||
const handleSavePress = () => {
|
||||
const name = newRecipeName.trim();
|
||||
if (!name) return;
|
||||
onSaveRecipe(name);
|
||||
setNewRecipeName('');
|
||||
setModalVisible(false);
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={{ paddingTop: insets.top + 6 }}
|
||||
className="absolute top-0 left-0 right-0 z-20 flex-row items-start justify-between px-4"
|
||||
>
|
||||
<View className="max-w-[62%] rounded-xl border border-zinc-800/80 bg-black/45 px-3 py-2">
|
||||
<Text className="text-amber-500 font-mono text-[9px] font-bold tracking-[0.2em]">
|
||||
{mode === 'camera' ? 'LIVE' : 'LIBRARY'}
|
||||
</Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
className="text-white font-mono text-sm font-bold tracking-wide"
|
||||
>
|
||||
{recipeName}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => setModalVisible(true)}
|
||||
className="flex-row items-center rounded-full border border-zinc-700/80 bg-black/45 px-4 py-2.5"
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Plus size={14} color="#f59e0b" />
|
||||
<Text className="ml-1 font-mono text-xs font-bold tracking-widest text-amber-500">
|
||||
SAVE
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Modal
|
||||
transparent
|
||||
animationType="slide"
|
||||
visible={modalVisible}
|
||||
onRequestClose={() => setModalVisible(false)}
|
||||
>
|
||||
<View className="flex-1 justify-end bg-black/60">
|
||||
<View style={{ paddingBottom: insets.bottom + 16 }} className="bg-titan border-t border-zinc-800 rounded-t-3xl p-6">
|
||||
<Text className="text-white font-mono text-sm font-bold tracking-wider mb-4">
|
||||
SAVE CURRENT AS RECIPE
|
||||
</Text>
|
||||
<TextInput
|
||||
value={newRecipeName}
|
||||
onChangeText={setNewRecipeName}
|
||||
placeholder="Recipe name (e.g. Fuji Retro)"
|
||||
placeholderTextColor="#71717a"
|
||||
className="bg-carbon border border-zinc-800 rounded-lg p-3 text-white font-mono text-sm mb-4"
|
||||
autoFocus
|
||||
onSubmitEditing={handleSavePress}
|
||||
/>
|
||||
<View className="flex-row space-x-3">
|
||||
<TouchableOpacity
|
||||
onPress={() => setModalVisible(false)}
|
||||
className="flex-1 bg-zinc-800 py-3 rounded-lg items-center"
|
||||
>
|
||||
<Text className="text-zinc-300 font-mono text-xs font-semibold">CANCEL</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={handleSavePress}
|
||||
className="flex-1 bg-amber-500 py-3 rounded-lg items-center"
|
||||
>
|
||||
<Text className="text-black font-mono text-xs font-bold">SAVE RECIPE</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user