Hello.
Following this tutorial: https://github.com/ionic-team/tutorial-photo-gallery-react
When I press the camera button in tab2.tsx, it does not open the camera to take a photo but it opens the photo gallery to select one. Why won’t the device camera open?
Could you please help me? I need to take a photo of the camera and not select it from the gallery
This is the code that I have taken and implemented
tabs2.tsx
import React, { useState } from 'react';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonFab, IonFabButton, IonIcon, IonGrid, IonRow, IonCol, IonImg, IonActionSheet } from '@ionic/react';
import { camera, trash, close } from 'ionicons/icons';
import { Photo, usePhotoGallery } from '../hooks/usePhotoGallery';
const Tab2: React.FC = () => {
const { deletePhoto, photos, takePhoto } = usePhotoGallery();
const [photoToDelete, setPhotoToDelete] = useState<Photo>();
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Photo Gallery</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Photo Gallery</IonTitle>
</IonToolbar>
</IonHeader>
<IonGrid>
<IonRow>
{photos.map((photo, index) => (
<IonCol size="6" key={index}>
<IonImg onClick={() => setPhotoToDelete(photo)} src={photo.webviewPath} />
</IonCol>
))}
</IonRow>
</IonGrid>
<IonFab vertical="bottom" horizontal="center" slot="fixed">
<IonFabButton onClick={() => takePhoto()}>
<IonIcon icon={camera}></IonIcon>
</IonFabButton>
</IonFab>
<IonActionSheet
isOpen={!!photoToDelete}
buttons={[{
text: 'Delete',
role: 'destructive',
icon: trash,
handler: () => {
if (photoToDelete) {
deletePhoto(photoToDelete);
setPhotoToDelete(undefined);
}
}
}, {
text: 'Cancel',
icon: close,
role: 'cancel'
}]}
onDidDismiss={() => setPhotoToDelete(undefined)}
/>
</IonContent>
</IonPage>
);
};
export default Tab2;
usePhotoGallery.ts
import { useState, useEffect } from "react";
import { useCamera } from '@ionic/react-hooks/camera';
import { useFilesystem, base64FromPath } from '@ionic/react-hooks/filesystem';
import { useStorage } from '@ionic/react-hooks/storage';
import { isPlatform } from '@ionic/react';
import { CameraResultType, CameraSource, CameraPhoto, Capacitor, FilesystemDirectory } from "@capacitor/core";
const PHOTO_STORAGE = "photos";
export function usePhotoGallery() {
const [photos, setPhotos] = useState<Photo[]>([]);
const { getPhoto } = useCamera();
const { deleteFile, readFile, writeFile } = useFilesystem();
const { get, set } = useStorage();
useEffect(() => {
const loadSaved = async () => {
const photosString = await get(PHOTO_STORAGE);
const photosInStorage = (photosString ? JSON.parse(photosString) : []) as Photo[];
// If running on the web...
if (!isPlatform('hybrid')) {
for (let photo of photosInStorage) {
const file = await readFile({
path: photo.filepath,
directory: FilesystemDirectory.Data
});
// Web platform only: Load the photo as base64 data
photo.webviewPath = `data:image/jpeg;base64,${file.data}`;
}
}
setPhotos(photosInStorage);
};
loadSaved();
}, [get, readFile]);
const takePhoto = async () => {
const cameraPhoto = await getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100
});
const fileName = new Date().getTime() + '.jpeg';
const savedFileImage = await savePicture(cameraPhoto, fileName);
const newPhotos = [savedFileImage, ...photos];
setPhotos(newPhotos);
set(PHOTO_STORAGE, JSON.stringify(newPhotos));
};
const savePicture = async (photo: CameraPhoto, fileName: string): Promise<Photo> => {
let base64Data: string;
// "hybrid" will detect Cordova or Capacitor;
if (isPlatform('hybrid')) {
const file = await readFile({
path: photo.path!
});
base64Data = file.data;
} else {
base64Data = await base64FromPath(photo.webPath!);
}
const savedFile = await writeFile({
path: fileName,
data: base64Data,
directory: FilesystemDirectory.Data
});
if (isPlatform('hybrid')) {
// Display the new image by rewriting the 'file://' path to HTTP
// Details: https://ionicframework.com/docs/building/webview#file-protocol
return {
filepath: savedFile.uri,
webviewPath: Capacitor.convertFileSrc(savedFile.uri),
};
}
else {
// Use webPath to display the new image instead of base64 since it's
// already loaded into memory
return {
filepath: fileName,
webviewPath: photo.webPath
};
}
};
const deletePhoto = async (photo: Photo) => {
// Remove this photo from the Photos reference data array
const newPhotos = photos.filter(p => p.filepath !== photo.filepath);
// Update photos array cache by overwriting the existing photo array
set(PHOTO_STORAGE, JSON.stringify(newPhotos));
// delete photo file from filesystem
const filename = photo.filepath.substr(photo.filepath.lastIndexOf('/') + 1);
await deleteFile({
path: filename,
directory: FilesystemDirectory.Data
});
setPhotos(newPhotos);
};
return {
deletePhoto,
photos,
takePhoto
};
}
export interface Photo {
filepath: string;
webviewPath?: string;
}
App.tsx
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import { IonApp, IonRouterOutlet, IonSplitPane } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import Home from './pages/Home';
/* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css';
/* Basic CSS for apps built with Ionic */
import '@ionic/react/css/normalize.css';
import '@ionic/react/css/structure.css';
import '@ionic/react/css/typography.css';
/* Optional CSS utils that can be commented out */
import '@ionic/react/css/padding.css';
import '@ionic/react/css/float-elements.css';
import '@ionic/react/css/text-alignment.css';
import '@ionic/react/css/text-transformation.css';
import '@ionic/react/css/flex-utils.css';
import '@ionic/react/css/display.css';
/* Theme variables */
import './theme/variables.css';
import Registro from './pages/Registro';
import Ingresar from './pages/Ingresar';
import Menu from './pages/Menu';
import MisServicios from './pages/MisServicios';
import Favoritos from './pages/Favoritos';
import HistorialServicios from './pages/HistorialServicios';
import Tab2 from './pages/Tabs2';
const App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonSplitPane contentId="main" when="(min-width: 4096px)">
<Menu />
<IonRouterOutlet id="main">
<Route path="/home" component={Home} exact={true} />
<Route exact path="/" render={() => <Redirect to="/home" />} />
<Route path="/registro" component={Registro} exact={true}></Route>
<Route path="/ingresar" component={Ingresar} exact={true}></Route>
<Route path="/MisServicios" component={MisServicios} exact={true}></Route>
<Route path="/Favoritos" component={Favoritos} exact={true}></Route>
<Route path="/HistorialServicios" component={HistorialServicios} exact={true}></Route>
<Route path="/tab2" component={Tab2} exact={true} />
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</IonApp>
);
export default App;