473 Create hold to delete photo interaction (#479)

* Create hold to delete photo interaction

* Delete w/o modal

* Clean code

* move delete back to review

* lint

---------

Co-authored-by: Johannes Klein <johannes.t.klein@gmail.com>
This commit is contained in:
Chris
2023-02-20 07:22:10 -06:00
committed by GitHub
parent 000e661ff5
commit dafe00bcce
2 changed files with 81 additions and 91 deletions

View File

@@ -1,7 +1,5 @@
// @flow
import MediaViewerModal from "components/MediaViewer/MediaViewerModal";
import DeletePhotoDialog from "components/SharedComponents/DeletePhotoDialog";
import PhotoCarousel from "components/SharedComponents/PhotoCarousel";
import { Text, View } from "components/styledComponents";
import { t } from "i18next";
@@ -23,8 +21,6 @@ const PhotoPreview = ( {
deviceOrientation
}: Props ): Node => {
const { deletePhotoFromObservation } = useContext( ObsEditContext );
const [deleteDialogVisible, setDeleteDialogVisible] = useState( false );
const [photoUriToDelete, setPhotoUriToDelete] = useState( null );
const [initialPhotoSelected, setInitialPhotoSelected] = useState( null );
const [mediaViewerVisible, setMediaViewerVisible] = useState( false );
@@ -36,16 +32,8 @@ const PhotoPreview = ( {
showModal( );
};
const showDialog = ( ) => setDeleteDialogVisible( true );
const hideDialog = ( ) => {
setPhotoUriToDelete( null );
setDeleteDialogVisible( false );
};
const handleDelete = photoUri => {
setPhotoUriToDelete( photoUri );
showDialog( );
const deletePhoto = photoUri => {
deletePhotoFromObservation( photoUri, photoUris, setPhotoUris );
};
const emptyDescription = ( ) => (
@@ -54,18 +42,8 @@ const PhotoPreview = ( {
</Text>
);
const deletePhoto = ( ) => {
deletePhotoFromObservation( photoUriToDelete, photoUris, setPhotoUris );
hideDialog( );
};
return (
<>
<DeletePhotoDialog
deleteDialogVisible={deleteDialogVisible}
deletePhoto={deletePhoto}
hideDialog={hideDialog}
/>
<MediaViewerModal
mediaViewerVisible={mediaViewerVisible}
hideModal={hideModal}
@@ -75,10 +53,10 @@ const PhotoPreview = ( {
/>
<View className="bg-black h-32">
<PhotoCarousel
deletePhoto={deletePhoto}
photoUris={photoUris}
emptyComponent={emptyDescription}
containerStyle="camera"
handleDelete={handleDelete}
setSelectedPhotoIndex={handleSelection}
savingPhoto={savingPhoto}
deviceOrientation={deviceOrientation}

View File

@@ -1,13 +1,18 @@
// @flow
import { Image, Pressable, View } from "components/styledComponents";
import classnames from "classnames";
import { ImageBackground, Pressable, View } from "components/styledComponents";
import type { Node } from "react";
import React from "react";
import React, {
useEffect, useState
} from "react";
import {
ActivityIndicator,
FlatList
} from "react-native";
import DeviceInfo from "react-native-device-info";
import LinearGradient from "react-native-linear-gradient";
import Modal from "react-native-modal";
import { IconButton, useTheme } from "react-native-paper";
import Icon from "react-native-vector-icons/MaterialIcons";
import colors from "styles/tailwindColors";
@@ -18,11 +23,11 @@ type Props = {
setSelectedPhotoIndex?: Function,
selectedPhotoIndex?: number,
containerStyle?: string,
handleDelete?: Function,
savingPhoto?: boolean,
handleAddEvidence?: Function,
showAddButton?: boolean,
deviceOrientation?: string
deviceOrientation?: string,
deletePhoto?: Function
}
const PhotoCarousel = ( {
@@ -31,41 +36,28 @@ const PhotoCarousel = ( {
setSelectedPhotoIndex,
selectedPhotoIndex,
containerStyle,
handleDelete,
savingPhoto,
handleAddEvidence,
showAddButton = false,
deviceOrientation
deviceOrientation,
deletePhoto
}: Props ): Node => {
const theme = useTheme( );
const [deletePhotoMode, setDeletePhotoMode] = useState( false );
const imageClass = "h-16 w-16 justify-center mx-1.5 rounded-lg";
const isTablet = DeviceInfo.isTablet();
const renderDeleteButton = photoUri => (
<IconButton
icon="trash-can"
iconColor={theme.colors.onPrimary}
containerColor={theme.colors.primary}
size={30}
onPress={( ) => {
if ( !handleDelete ) { return; }
handleDelete( photoUri );
}}
className="absolute top-10 right-0"
/>
);
const renderSkeleton = ( ) => {
if ( savingPhoto ) {
return (
<View className={`${imageClass} bg-midGray mt-12`}>
<ActivityIndicator />
</View>
);
useEffect( () => {
if ( photoUris.length === 0 && deletePhotoMode ) {
setDeletePhotoMode( false );
}
return null;
};
}, [photoUris.length, deletePhotoMode] );
const renderSkeleton = ( ) => ( savingPhoto ? (
<View className={`${imageClass} bg-midGray mt-12`}>
<ActivityIndicator />
</View>
) : null );
const renderPhotoOrEvidenceButton = ( { item, index } ) => {
if ( index === photoUris.length ) {
@@ -79,49 +71,55 @@ const PhotoCarousel = ( {
);
}
const setClassName = ( ) => {
let className = imageClass;
if ( containerStyle === "camera" ) {
className += " mt-12";
} else {
className += " mt-6";
}
if ( selectedPhotoIndex === index ) {
className += " border border-selectionGreen border-4";
}
return className;
};
const imageClassName = () => {
let className = "w-fit h-full ";
if ( deviceOrientation && !isTablet ) {
if ( deviceOrientation === "portrait" ) {
className += "rotate-0";
} else if ( deviceOrientation === "landscapeLeft" ) {
className += "-rotate-90";
} else if ( deviceOrientation === "landscapeRight" ) {
className += "rotate-90";
}
}
return className;
};
return (
<>
<Pressable
onLongPress={( ) => {
if ( deletePhoto ) {
setDeletePhotoMode( mode => !mode );
}
}}
onPress={( ) => {
if ( setSelectedPhotoIndex ) {
if ( deletePhotoMode && deletePhoto ) {
deletePhoto( item );
} else if ( setSelectedPhotoIndex ) {
setSelectedPhotoIndex( index );
}
}}
className={setClassName( )}
className={classnames( imageClass, {
"mt-12": containerStyle === "camera",
"mt-6": containerStyle !== "camera",
"border border-selectionGreen border-4":
selectedPhotoIndex === index
} )}
>
<Image
source={{ uri: item }}
testID="ObsEdit.photo"
className={imageClassName()}
/>
{( containerStyle === "camera" ) && renderDeleteButton( item )}
<View className="rounded-lg overflow-hidden">
<ImageBackground
source={{ uri: item }}
testID="ObsEdit.photo"
className={classnames( "w-fit h-full flex items-center justify-center", {
"rotate-0": deviceOrientation === "portrait" && !isTablet,
"-rotate-90": deviceOrientation === "landscapeLeft" && !isTablet,
"rotate-90": deviceOrientation === "landscapeRight" && !isTablet
} )}
>
{deletePhotoMode && (
<LinearGradient
className="bg-transparent absolute inset-0"
colors={["rgba(0, 0, 0, 0.5)", "rgba(0, 0, 0, 0.5)"]}
/>
)}
{( containerStyle === "camera" && deletePhotoMode ) && (
<IconButton
icon="trash-can"
mode="contained-tonal"
iconColor={theme.colors.onPrimary}
containerColor="rgba(0, 0, 0, 0.5)"
size={30}
/>
)}
</ImageBackground>
</View>
</Pressable>
{index === photoUris.length - 1 && renderSkeleton( )}
</>
@@ -131,7 +129,7 @@ const PhotoCarousel = ( {
const data = [...photoUris];
if ( showAddButton ) data.push( "add" );
return (
const photoPreviewsList = (
<FlatList
data={data}
renderItem={renderPhotoOrEvidenceButton}
@@ -139,6 +137,20 @@ const PhotoCarousel = ( {
ListEmptyComponent={savingPhoto ? renderSkeleton( ) : emptyComponent}
/>
);
return deletePhotoMode ? (
<Modal
visible
onBackdropPress={() => setDeletePhotoMode( false )}
backdropOpacity={0}
// eslint-disable-next-line react-native/no-inline-styles
style={{ margin: 0 }}
>
<View className="absolute top-0">
{photoPreviewsList}
</View>
</Modal>
) : photoPreviewsList;
};
export default PhotoCarousel;