From a01e472c7f6084cb7e66aa2d6bef750dc30dca90 Mon Sep 17 00:00:00 2001 From: LijuJacob08 Date: Tue, 29 Oct 2024 02:20:39 +0530 Subject: [PATCH] list audio resources and added delete button to delete the resource --- App.tsx | 6 +- screens/HomeScreen.tsx | 12 +- screens/ImportModal.tsx | 2 +- screens/ImportResourcePage.tsx | 208 +++++++++++++++++++------------- screens/ListAudioPage.tsx | 176 +++++++++++++++++++++++++-- screens/ListBiblePage.tsx | 127 +++++++++++++++++-- screens/ProjectEditorScreen.tsx | 56 ++------- 7 files changed, 434 insertions(+), 153 deletions(-) diff --git a/App.tsx b/App.tsx index d03606d..9afc009 100644 --- a/App.tsx +++ b/App.tsx @@ -23,7 +23,7 @@ export type RootStackParamList = { 'Sign up': undefined; CreateProject: undefined; ReferencePage: undefined; - ProjectEditor: {projectId: string; projectName: string ,projectPath:string,referenceRes:string}; + ProjectEditor: {projectId: string; projectName: string ,projectPath:string,referenceResource:string}; }; const Stack = createStackNavigator(); @@ -41,11 +41,11 @@ export default function App() { permission = isManagePermitted; }); // request rights to manage - if (permission===false) { + // if (permission===false) { requestManagePermission().then(isManagePermitted => { console.log("Permission for file access granted",isManagePermitted); }); - } + // } const checkAndCreateFolderAndFile = async () => { const folderPath = `${RNFS.ExternalStorageDirectoryPath}/Download/OBTRecorderApp`; const filePath = `${folderPath}/appInfo.json`; diff --git a/screens/HomeScreen.tsx b/screens/HomeScreen.tsx index 0104485..73666b5 100644 --- a/screens/HomeScreen.tsx +++ b/screens/HomeScreen.tsx @@ -60,11 +60,11 @@ const HomeScreen: React.FC = ({navigation}) => { const appInfo = JSON.parse(fileContent); if (appInfo.projects && Array.isArray(appInfo.projects)) { - const loadedProjects = appInfo.projects.map((project, index) => ({ + const loadedProjects = appInfo.projects.map((project: { projectName: any; projectPath: any; referenceResource: any; }, index: number) => ({ id: `${index + 1}`, name: project.projectName, path: project.projectPath, - reference:project.ReferenceResource, + reference:project.referenceResource, })); setProjects(loadedProjects); } else { @@ -91,11 +91,11 @@ const HomeScreen: React.FC = ({navigation}) => { const appInfo = JSON.parse(fileContent); if (appInfo.projects && Array.isArray(appInfo.projects)) { - const loadedProjects = appInfo.projects.map((project, index) => ({ + const loadedProjects = appInfo.projects.map((project: { projectName: any; projectPath: any; referenceResource: any; }, index: number) => ({ id: `${index + 1}`, name: project.projectName, path: project.projectPath, - reference: project.ReferenceResource + reference: project.referenceResource })); setProjects(loadedProjects); } else { @@ -162,7 +162,7 @@ const HomeScreen: React.FC = ({navigation}) => { }; const navigateToProjectEditor = (id: string, name: string , path:string, reference:string) => { - navigation.navigate('ProjectEditor', {projectId: id, projectName: name, projectPath:path, referenceRes:reference}); + navigation.navigate('ProjectEditor', {projectId: id, projectName: name, projectPath:path, referenceResource:reference}); }; const handleImport = async (folderPath: string) => { @@ -363,7 +363,7 @@ const styles = StyleSheet.create({ borderBottomColor: '#ddd', }, drawerStyle: { - // backgroundColor: '#000', + backgroundColor: '#2f3542', position: 'absolute', right: 0, width: '45%', diff --git a/screens/ImportModal.tsx b/screens/ImportModal.tsx index 6d4c6de..885e5c4 100644 --- a/screens/ImportModal.tsx +++ b/screens/ImportModal.tsx @@ -237,7 +237,7 @@ const ImportModal: React.FC = ({ Please wait. Importing Project in progress... - {convertingFileMessage} + {convertingFileMessage} ) : selectedFolder ? ( diff --git a/screens/ImportResourcePage.tsx b/screens/ImportResourcePage.tsx index 43dcfe6..484844f 100644 --- a/screens/ImportResourcePage.tsx +++ b/screens/ImportResourcePage.tsx @@ -6,47 +6,61 @@ import { StyleSheet, Alert, Modal, + ActivityIndicator, } from 'react-native'; -import {TextInput} from 'react-native-paper'; +import {TextInput, Dialog, Portal, Button} from 'react-native-paper'; import {SvgXml} from 'react-native-svg'; import RNFS from 'react-native-fs'; -import {Portal} from 'react-native-paper'; // Import Portal -// import ImportReferenceCollectionModal from './ImportReferenceCollectionModal'; -import FolderPicker from './FolderPicker'; const grammar = require('usfm-grammar'); +import FolderPicker from './FolderPicker'; -const ImportResourcePage: React.FC = () => { - // const [importCollectionDialogVisible, setImportCollectionDialogVisible] = - // useState(false); - // const [updateCollection, setUpdateCollection] = useState(false); - - // const handleImportCollection = async (folderPath: string) => { - // console.log('Imported folder path:', folderPath); - // }; +interface AppInfo { + references?: { + referenceName: string; + referencePath: string; + referenceType: string[]; + }[]; +} + +interface Ingredient { + mimeType?: string; + mime_type?: string; +} + +// Type guard to check if an object is of type `Ingredient` +const isIngredient = (obj: any): obj is Ingredient => { + return ( + typeof obj === 'object' && + obj !== null && + ('mimeType' in obj || 'mime_type' in obj) + ); +}; +const ImportResourcePage = () => { const folderIcon = ''; const infoIcon = ''; - const [showFolderPicker, setShowFolderPicker] = useState(false); - const [selectedFolder, setSelectedFolder] = useState(''); - const [fileTransferMessage, setFileTransferMessage] = useState(''); - const [isImporting, setIsImporting] = useState(false); - // const [startTime, setStartTime] = useState(null); - // const [endTime, setEndTime] = useState(null); + const [showFolderPicker, setShowFolderPicker] = useState(false); + const [selectedFolder, setSelectedFolder] = useState(''); + const [isImporting, setIsImporting] = useState(false); + const [fileTransferMessage, setFileTransferMessage] = useState(''); + const [showImportDialog, setShowImportDialog] = useState(false); - const handleSelectFolder = (path: string) => { + const handleSelectFolder = (path: React.SetStateAction) => { setSelectedFolder(path); setShowFolderPicker(false); - // onImport(path); + setShowImportDialog(true); + }; + + const handleCancel = () => { + setSelectedFolder(''); + setShowImportDialog(false); }; - const convertUsfmToJson = async ( - sourcePath: string, - destinationPath: string, - ) => { + const convertUsfmToJson = async (sourcePath: string, destinationPath: string) => { const usfmContent = await RNFS.readFile(sourcePath, 'utf8'); const usfmParser = new grammar.USFMParser(usfmContent); const usfmJson = usfmParser.toJSON(); @@ -57,12 +71,10 @@ const ImportResourcePage: React.FC = () => { const copyDirectory = async (source: string, destination: string) => { const items = await RNFS.readDir(source); - await RNFS.mkdir(destination); for (const item of items) { const itemDestination = `${destination}/${item.name}`; - if (item.isDirectory()) { await copyDirectory(item.path, itemDestination); } else if ( @@ -70,7 +82,8 @@ const ImportResourcePage: React.FC = () => { item.name.toLowerCase().endsWith('.sfm') ) { console.log(`Converting file: ${item.path}`); - setFileTransferMessage(`transferring file: ${item.path}`) + let chars = item.path.split('/'); + setFileTransferMessage(`Importing file: ${chars[chars.length - 1]}`); await convertUsfmToJson(item.path, itemDestination); } else { await RNFS.copyFile(item.path, itemDestination); @@ -87,34 +100,26 @@ const ImportResourcePage: React.FC = () => { const metadataContent = await RNFS.readFile(metadataFilePath); const metadata = JSON.parse(metadataContent); - if ( - metadata && - metadata.identification && - metadata.identification.name - ) { + if (metadata && metadata.identification && metadata.identification.name) { const projectName = metadata.identification.name.en; - const baseFolderPath = '/storage/emulated/0/Download/OBTRecorderApp'; const referenceFolderPath = `${baseFolderPath}/references`; const jsonFilePath = `${baseFolderPath}/appInfo.json`; const fileExists = await RNFS.exists(jsonFilePath); - let appInfo: any = {}; + let appInfo: AppInfo = {}; - // If the appInfo file exists, read it; otherwise, initialize appInfo if (fileExists) { const appInfoContent = await RNFS.readFile(jsonFilePath); - appInfo = JSON.parse(appInfoContent); + appInfo = JSON.parse(appInfoContent) as AppInfo; } - // Ensure the `references` array exists if (!appInfo.references) { - appInfo.references = []; // Initialize the references array if it doesn't exist + appInfo.references = []; } - // Check if a project with the same name already exists const projectExists = appInfo.references.some( - (reference: any) => reference.projectName === projectName, + (reference) => reference.referenceName === projectName, ); if (projectExists) { @@ -123,19 +128,39 @@ const ImportResourcePage: React.FC = () => { return; } - // Check if text-1/ingredients folder exists with .usfm or .sfm files + let referenceType: string[] = []; + + if (metadata.ingredients) { + const hasAudioFiles = Object.values(metadata.ingredients).some( + (ingredient) => { + if (isIngredient(ingredient)) { + const mimeType = ingredient.mimeType || ingredient.mime_type; + return ( + mimeType && + (mimeType.startsWith('audio/') || + mimeType.includes('wav') || + mimeType.includes('mp3')) + ); + } + return false; + }, + ); + + if (hasAudioFiles) { + referenceType.push('Audio'); + } + } + const text1FolderPath = `${selectedFolder}/text-1`; const ingredientsFolderPath = `${text1FolderPath}/ingredients`; const text1Exists = await RNFS.exists(text1FolderPath); - let referenceType = []; - if (text1Exists) { const ingredientsExists = await RNFS.exists(ingredientsFolderPath); if (ingredientsExists) { const ingredientFiles = await RNFS.readDir(ingredientsFolderPath); const hasUsfmOrSfm = ingredientFiles.some( - file => + (file) => file.name.toLowerCase().endsWith('.usfm') || file.name.toLowerCase().endsWith('.sfm'), ); @@ -146,7 +171,6 @@ const ImportResourcePage: React.FC = () => { } } - // Ensure the references folder exists const referenceResourceFolderExists = await RNFS.exists( referenceFolderPath, ); @@ -154,25 +178,20 @@ const ImportResourcePage: React.FC = () => { await RNFS.mkdir(referenceFolderPath); } - // Copy the selected folder and its contents to the destination const destinationPath = `${referenceFolderPath}/${projectName}`; await copyDirectory(selectedFolder, destinationPath); - // Create the new project object const newProject = { referenceName: projectName, referencePath: destinationPath, referenceType: referenceType, }; - // Add the new project to the references array appInfo.references.push(newProject); - - // Save the updated appInfo.json file await RNFS.writeFile(jsonFilePath, JSON.stringify(appInfo, null, 2)); - setFileTransferMessage(""); + setFileTransferMessage(''); handleCancel(); - Alert.alert('Success', 'Project imported successfully.'); + Alert.alert('Success', 'Reference imported successfully.'); } else { Alert.alert('Error', 'Invalid metadata file.'); } @@ -182,37 +201,15 @@ const ImportResourcePage: React.FC = () => { } finally { setIsImporting(false); const endTime = Date.now(); - - const elapsedTime = endTime - startTime; - const seconds = Math.floor(elapsedTime / 1000); - const minutes = Math.floor(seconds / 60); - const hours = Math.floor(minutes / 60); - const secondsRemaining = seconds % 60; - const minutesRemaining = minutes % 60; - - const hoursString = hours > 0 ? `${hours}h ` : ''; - const minutesString = - minutesRemaining > 0 ? `${minutesRemaining}m ` : ''; - const secondsString = - secondsRemaining > 0 ? `${secondsRemaining}s` : ''; - - console.log('elapsed time', elapsedTime); - console.log( - `Import time: ${hoursString} : ${minutesString} : ${secondsString}`, - ); + console.log('Import time:', endTime - startTime, 'ms'); } } else { Alert.alert('Error', 'No folder selected.'); } }; - const handleCancel = () => { - setSelectedFolder(''); - // onDismiss(); - }; - return ( - + IMPORT RESOURCE @@ -225,12 +222,12 @@ const ImportResourcePage: React.FC = () => { style={styles.textInput} value={selectedFolder} disabled - // multiline={true} textColor="#000" /> setShowFolderPicker(true)}> + onPress={() => setShowFolderPicker(true)} + disabled={isImporting}> Select Folder @@ -238,13 +235,41 @@ const ImportResourcePage: React.FC = () => { + style={[styles.uploadButton, isImporting && styles.disabledButton]} + onPress={() => setShowImportDialog(true)} + disabled={!selectedFolder || isImporting}> Upload + + Import Reference + + {isImporting ? ( + + + + Please wait. Importing Reference in progress... + + {fileTransferMessage} + + ) : ( + + + Selected Folder: {selectedFolder} + + + + )} + + + + + + { + const [data, setData] = useState([]); + const baseFolderPath = '/storage/emulated/0/Download/OBTRecorderApp'; + const appInfoPath = `${baseFolderPath}/appInfo.json`; + + const deleteIcon = ` + + + +`; + + +const handleDelete = async (itemName: string) => { + try { + // Read current appInfo.json + const appInfoContent = await RNFS.readFile(appInfoPath, 'utf8'); + const appInfo: AppInfo = JSON.parse(appInfoContent); + + // Check if any project is using this reference + const projectsUsingReference = appInfo.projects.filter( + project => project.referenceResource === itemName + ); + + if (projectsUsingReference.length > 0) { + Alert.alert( + 'Warning', + `This reference is being used by ${projectsUsingReference.length} project(s). Are you sure you want to delete it?`, + [ + { + text: 'Cancel', + style: 'cancel' + }, + { + text: 'Yes', + onPress: () => performDelete(itemName, appInfo) + } + ] + ); + } else { + performDelete(itemName, appInfo); + } + } catch (error) { + console.error('Error handling delete:', error); + Alert.alert('Error', 'Failed to delete reference'); + } +}; + +const performDelete = async (itemName: string, appInfo: AppInfo) => { + try { + // Delete the reference folder + const referencePath = `${baseFolderPath}/references/${itemName}`; + await RNFS.unlink(referencePath); + + // Update projects that use this reference + appInfo.projects = appInfo.projects.map(project => { + if (project.referenceResource === itemName) { + return { ...project, referenceResource: '' }; + } + return project; + }); + + // Remove the reference from references array + appInfo.references = appInfo.references.filter( + ref => ref.referenceName !== itemName + ); + + // Write updated appInfo back to file + await RNFS.writeFile(appInfoPath, JSON.stringify(appInfo, null, 2)); + + // Update the UI + setData(prevData => prevData.filter(item => item.name !== itemName)); + + Alert.alert('Success', 'Reference deleted successfully'); + } catch (error) { + console.error('Error performing delete:', error); + Alert.alert('Error', 'Failed to delete reference'); + } +}; + + + + useEffect(() => { + // Function to load references from appInfo.json + const loadReferences = async () => { + try { + // const appInfoPath = `${RNFS.DownloadDirectoryPath}/appInfo.json`; + const appInfo = await RNFS.readFile(appInfoPath, 'utf8'); + const parsedInfo = JSON.parse(appInfo); + + const references = parsedInfo.references || []; + const tableData: TableData[] = []; + + for (const reference of references) { + const metadataPath = `${reference.referencePath}/metadata.json`; + if (await RNFS.exists(metadataPath)) { + const metadata = JSON.parse( + await RNFS.readFile(metadataPath, 'utf8'), + ); + const {languages, version,identification} = metadata; + if(reference.referenceType.includes("Audio")) + { + const primaryKey = Object.keys(identification.primary)[0]; // Gets "scribe" (or the unknown key) + const uniqueId = Object.keys(identification.primary[primaryKey])[0]; // Gets the UUID + + tableData.push({ + name: reference.referenceName, + type: (reference.referenceType.includes("Bible") && reference.referenceType.includes("Audio")) ?'Both':'Audio' , + // type: type || 'Unknown', + languageName: languages[0].name.en || 'Unknown', + version: uniqueId || 'Unknown', + });} + } else { + Alert.alert( + 'Metadata not found', + `Metadata file not found for ${reference.referenceName}`, + ); + } + } + + setData(tableData); + } catch (error) { + console.error('Error loading references:', error); + } + }; + + loadReferences(); + }, []); const renderItem = ({item}: {item: TableData}) => ( {item.name} {item.type} {item.languageName} - {item.col4} + {item.version} + handleDelete(item.name)} + > + + {/* {item.col5} {item.col6} */} - {item.col7} + {/* {item.col7} */} ); @@ -51,10 +207,11 @@ const ListAudioPage: React.FC = () => { Name Type Language Name - + Version + Action {/* */} - + {/* */} { const [data, setData] = useState([]); + const baseFolderPath = '/storage/emulated/0/Download/OBTRecorderApp'; + const appInfoPath = `${baseFolderPath}/appInfo.json`; + + // Delete icon SVG + const deleteIcon = ` + + + + `; useEffect(() => { // Function to load references from appInfo.json const loadReferences = async () => { try { // const appInfoPath = `${RNFS.DownloadDirectoryPath}/appInfo.json`; - const baseFolderPath = '/storage/emulated/0/Download/OBTRecorderApp'; - const appInfoPath = `${baseFolderPath}/appInfo.json`; + // const baseFolderPath = '/storage/emulated/0/Download/OBTRecorderApp'; + // const appInfoPath = `${baseFolderPath}/appInfo.json`; const appInfo = await RNFS.readFile(appInfoPath, 'utf8'); const parsedInfo = JSON.parse(appInfo); @@ -31,15 +60,20 @@ const ListBiblePage: React.FC = () => { const metadata = JSON.parse( await RNFS.readFile(metadataPath, 'utf8'), ); - const {languages, version} = metadata; - + const {languages, identification} = metadata; + if(reference.referenceType.includes("Bible")) + { + const primaryKey = Object.keys(identification.primary)[0]; // Gets "scribe" (or the unknown key) + const uniqueId = Object.keys(identification.primary[primaryKey])[0]; // Gets the UUID + tableData.push({ name: reference.referenceName, - type: 'Bible', + type: (reference.referenceType.includes("Bible") && reference.referenceType.includes("Audio")) ?'Both':'Bible' , // type: type || 'Unknown', languageName: languages[0].name.en || 'Unknown', - version: version || 'Unknown', + version: uniqueId || 'Unknown', }); + } } else { Alert.alert( 'Metadata not found', @@ -57,12 +91,85 @@ const ListBiblePage: React.FC = () => { loadReferences(); }, []); + const handleDelete = async (itemName: string) => { + try { + // Read current appInfo.json + const appInfoContent = await RNFS.readFile(appInfoPath, 'utf8'); + const appInfo: AppInfo = JSON.parse(appInfoContent); + + // Check if any project is using this reference + const projectsUsingReference = appInfo.projects.filter( + project => project.referenceResource === itemName + ); + + if (projectsUsingReference.length > 0) { + Alert.alert( + 'Warning', + `This reference is being used by ${projectsUsingReference.length} project(s). Are you sure you want to delete it?`, + [ + { + text: 'Cancel', + style: 'cancel' + }, + { + text: 'Yes', + onPress: () => performDelete(itemName, appInfo) + } + ] + ); + } else { + performDelete(itemName, appInfo); + } + } catch (error) { + console.error('Error handling delete:', error); + Alert.alert('Error', 'Failed to delete reference'); + } + }; + + const performDelete = async (itemName: string, appInfo: AppInfo) => { + try { + // Delete the reference folder + const referencePath = `${baseFolderPath}/references/${itemName}`; + await RNFS.unlink(referencePath); + + // Update projects that use this reference + appInfo.projects = appInfo.projects.map(project => { + if (project.referenceResource === itemName) { + return { ...project, referenceResource: '' }; + } + return project; + }); + + // Remove the reference from references array + appInfo.references = appInfo.references.filter( + ref => ref.referenceName !== itemName + ); + + // Write updated appInfo back to file + await RNFS.writeFile(appInfoPath, JSON.stringify(appInfo, null, 2)); + + // Update the UI + setData(prevData => prevData.filter(item => item.name !== itemName)); + + Alert.alert('Success', 'Reference deleted successfully'); + } catch (error) { + console.error('Error performing delete:', error); + Alert.alert('Error', 'Failed to delete reference'); + } + }; + const renderItem = ({item}: {item: TableData}) => ( {item.name} {item.type} {item.languageName} {item.version} + handleDelete(item.name)} + > + + ); @@ -73,6 +180,7 @@ const ListBiblePage: React.FC = () => { Type Language Name Version + Action = ({ navigation, route }) => { const jsonFilePath = `${baseFolderPath}/appInfo.json`; const [referenceType, setReferenceType] = useState([]); const [selectedRef, setSelectedRef] = useState(null); - const { projectId, projectName, projectPath, referenceRes } = route.params; + const { projectId, projectName, projectPath, referenceResource } = route.params; const [selectedBook, setSelectedBook] = useState(''); const [selectedChapter, setSelectedChapter] = useState(1); const [selectedVerse, setSelectedVerse] = useState(1); @@ -89,17 +89,6 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { setFontSize(prevSize => (prevSize > 14 ? prevSize - 1 : prevSize)); }; - - // useEffect(() => { - // navigation.setOptions({ - // headerRight: () => ( - // // - // // = 20 ? '#d3d3d3' : '#ff9f1a'} /> - // // - // // - // ), - // }); - // }, [navigation,fontSize]); // Load reference metadata useEffect(() => { const loadReferenceMetadata = async () => { @@ -166,25 +155,7 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { } }, [refreshMetadata, loadProjectMetadata]); - // const generateAudioUrl = () => { - // if (selectedRef && selectedBook && selectedChapter && selectedVerse && metadata) { - // const formattedChapter = selectedChapter.toString(); - // const formattedVerse = selectedVerse.toString(); - // const audioFileName = `${formattedChapter}_${formattedVerse}.wav`; - // const ingredientPath = `audio/ingredients/${selectedBook}/${formattedChapter}/${audioFileName}`; - - // // Check if the audio file exists in the metadata - // if (metadata.ingredients && metadata.ingredients[ingredientPath]) { - // const url = `${selectedRef.path}/${ingredientPath}`; - // setAudioUrl(url); - // } else { - // console.log(`Audio file not found in metadata: ${ingredientPath}`); - // setAudioUrl(null); - // } - // } else { - // setAudioUrl(null); - // } - // }; + const generateAudioUrls = useCallback(() => { if (selectedBook && selectedChapter && selectedVerse) { const formattedChapter = selectedChapter.toString(); @@ -271,7 +242,9 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { path: ref.referencePath, })); setReferenceType(formattedReferences); - const defaultRef = formattedReferences.find(ref => ref.title === referenceRes); + console.log(formattedReferences,"formattedReferences",referenceResource) + const defaultRef = formattedReferences.find(ref => ref.title === referenceResource); + console.log(referenceResource,"defaultRef") setSelectedRef(defaultRef); } else { setReferenceType([{ title: 'No option available', path: null }]); @@ -284,7 +257,7 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { console.log('Error reading JSON file:', error); setReferenceType([{ title: 'No option available', path: null }]); } - }, [jsonFilePath, referenceRes]); + }, [jsonFilePath, referenceResource]); const loadVerseText = useCallback( @@ -449,7 +422,7 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { if (project.projectName === projectName) { return { ...project, - ReferenceResource: selectedReference.title + referenceResource: selectedReference.title }; } return project; @@ -471,11 +444,7 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { return ( - {/* */} - {/* */} - {/* */} - - + {currentScope && @@ -486,8 +455,6 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { style={{ alignItems: 'center', height: isPortrait ? '90%' : '80%', - // backgroundColor: '#ddd' - // borderWidth:1 }}> = ({ navigation, route }) => { style={ // styles.cardTitleContainer,[] { - - // border:1, - // padding: 3, - // backgroundColor:'#ecf0f1', - // borderBottomColor:'#95a5a6' flexDirection:'row', alignItems:'center', height: 50, @@ -544,7 +506,7 @@ const ProjectEditorScreen: React.FC = ({ navigation, route }) => { updateAppInfoJson(selectedItem); } }} - buttonTextAfterSelection={(selectedItem) => { + buttonTextAfterSelection={(selectedItem: { title: any; }) => { return selectedItem ? selectedItem.title : 'Select Reference'; }} rowTextForSelection={(item) => {