import { useHeaderHeight } from "@react-navigation/elements" import { BlurView } from "expo-blur" import { router } from "expo-router" import { useRef, useState } from "react" import { KeyboardAvoidingView, Platform, Pressable, ScrollView, Text, TextInput, View, } from "react-native" import { useSafeAreaInsets } from "react-native-safe-area-context" import NoteImagePanel from "@/components/note-image-panel" import UploadProgressBar from "@/components/upload-progress-bar" import { useNotes } from "@/src/notes/NotesContext" import { StagedNoteImage, validateStagedNoteImage } from "@/src/notes/image-utils" import { pickImageFromCamera, pickImageFromLibrary } from "@/src/notes/native-image-picker" import { usePickerLifecycleGuard } from "@/src/notes/use-picker-lifecycle-guard" import { newNoteScreenStyles as styles } from "@/src/styles/app-styles" import { useAppTheme } from "@/src/theme/AppThemeProvider" export default function NewNoteScreen() { const { addNote, errorMessage } = useNotes() const [title, setTitle] = useState("") const [content, setContent] = useState("") const [stagedImage, setStagedImage] = useState(null) const [isSaving, setIsSaving] = useState(false) const [uploadProgress, setUploadProgress] = useState(null) const [localErrorMessage, setLocalErrorMessage] = useState(null) const insets = useSafeAreaInsets() const headerHeight = useHeaderHeight() const { colorScheme, palette } = useAppTheme() const [contentHeight, setContentHeight] = useState(160) const scrollRef = useRef(null) const { endPicker, isScreenActive, tryBeginPicker } = usePickerLifecycleGuard() const attachFromCamera = async () => { if (!tryBeginPicker()) { return } try { const image = await pickImageFromCamera() if (image && isScreenActive()) { validateStagedNoteImage(image) setStagedImage(image) setLocalErrorMessage(null) } } catch (error) { if (isScreenActive()) { setLocalErrorMessage(error instanceof Error ? error.message : "The camera could not be opened.") } } finally { endPicker() } } const attachFromGallery = async () => { if (!tryBeginPicker()) { return } try { const image = await pickImageFromLibrary() if (image && isScreenActive()) { validateStagedNoteImage(image) setStagedImage(image) setLocalErrorMessage(null) } } catch (error) { if (isScreenActive()) { setLocalErrorMessage(error instanceof Error ? error.message : "The gallery could not be opened.") } } finally { endPicker() } } const onSave = async () => { if (!title.trim() || !content.trim()) { setLocalErrorMessage("Title and content are required.") return } setIsSaving(true) setUploadProgress(null) setLocalErrorMessage(null) const wasSaved = await addNote(title, content, stagedImage, { onImageUploadProgress: (progress) => { setUploadProgress(progress.progress) }, }) setIsSaving(false) setUploadProgress(null) if (wasSaved) { if (router.canGoBack()) { router.back() return } router.replace("/") } } const saveDisabled = isSaving const imageActionsDisabled = isSaving const saveButtonStyle = saveDisabled ? styles.disabledButton : styles.enabledButtonShadow return ( { setContentHeight(e.nativeEvent.contentSize.height) scrollRef.current?.scrollToEnd({ animated: true }) }} /> { void attachFromCamera() }} onChooseFromLibrary={() => { void attachFromGallery() }} onRemoveImage={() => { setStagedImage(null) setLocalErrorMessage(null) }} /> {uploadProgress !== null ? : null} {localErrorMessage ? ( {localErrorMessage} ) : null} {!localErrorMessage && errorMessage ? ( {errorMessage} ) : null} { void onSave() }} style={[styles.saveButton, saveButtonStyle, { backgroundColor: palette.accent }]} > {isSaving ? "Saving..." : "Save note"} ) }