import React, { useMemo, useState } from 'react'; import { View, Text, Modal, ScrollView, TouchableOpacity, Linking } from 'react-native'; import { X, ChevronDown, ChevronRight, ExternalLink, Scale } from 'lucide-react-native'; import { CREDITS, LICENSE_TEXTS, CreditEntry } from '../utils/credits'; // About + open-source credits, reachable from the settings sheet. Third-party // data is generated from node_modules (src/utils/credits.ts + THIRD_PARTY_NOTICES.md); // each project row links to its homepage, each license group expands to the // full license text embedded in the app. const APP_NAME = 'recipescamera'; const APP_VERSION = '1.2'; // keep in sync with app.json function Group({ license, entries, }: { license: string; entries: CreditEntry[]; }) { const [open, setOpen] = useState(false); const text = LICENSE_TEXTS[license]; return ( setOpen((v) => !v)} className="flex-row items-center justify-between px-3 py-2.5" activeOpacity={0.7} > {license} {entries.length} {entries.length === 1 ? 'component' : 'components'} {open ? ( ) : ( )} {open && ( {entries.map((e) => ( {e.name} {e.url.startsWith('http') && ( Linking.openURL(e.url)} accessibilityLabel={`Open ${e.name} project page`} className="flex-row items-center" hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }} > )} {e.copyright ? ( {e.copyright} ) : null} {e.version} ))} {text ? ( {text} ) : null} )} ); } export default function CreditsModal({ visible, onClose, }: { visible: boolean; onClose: () => void; }) { const groups = useMemo(() => { const byLicense = new Map(); for (const e of CREDITS) { const arr = byLicense.get(e.license) ?? []; arr.push(e); byLicense.set(e.license, arr); } // stable order: licenses as declared in LICENSE_TEXTS, then rest const order = Object.keys(LICENSE_TEXTS); const sorted = [...byLicense.keys()].sort( (a, b) => order.indexOf(a) - order.indexOf(b) ); return sorted .filter((k) => byLicense.has(k)) .map((k) => ({ license: k, entries: byLicense.get(k)! })); }, []); return ( ABOUT & CREDITS {APP_NAME} version {APP_VERSION} · film-recipe camera (experimental) Author: Lộc Phạm Linking.openURL('mailto:tranloclqd@gmail.com')} accessibilityLabel="Email author" className="flex-row items-center ml-3" hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }} > tranloclqd@gmail.com © 2026 Lộc Phạm · Built with React Native + Expo; icons by Lucide; on-screen graphics rendered with Skia. {groups.map((g) => ( ))} ); }