diff --git a/src/components/AddObsBottomSheet/AddObsBottomSheet.tsx b/src/components/AddObsBottomSheet/AddObsBottomSheet.tsx
new file mode 100644
index 000000000..a3e000de7
--- /dev/null
+++ b/src/components/AddObsBottomSheet/AddObsBottomSheet.tsx
@@ -0,0 +1,175 @@
+import classNames from "classnames";
+import {
+ Body3, BottomSheet, INatIconButton
+} from "components/SharedComponents";
+import { View } from "components/styledComponents";
+import React, { useMemo } from "react";
+import { Platform, TouchableOpacity } from "react-native";
+import Observation from "realmModels/Observation";
+import { useTranslation } from "sharedHooks";
+import useStore from "stores/useStore";
+import { getShadow } from "styles/global";
+import colors from "styles/tailwindColors";
+
+interface Props {
+ closeModal: ( ) => void;
+ navAndCloseModal: ( screen: string, params?: {
+ camera?: string
+ } ) => void;
+ hidden: boolean;
+}
+
+export type ObsCreateItem = {
+ text?: string,
+ icon: string,
+ onPress: ( ) => void,
+ testID: string,
+ className: string,
+ accessibilityLabel: string,
+ accessibilityHint: string
+}
+
+const majorVersionIOS = parseInt( String( Platform.Version ), 10 );
+const AI_CAMERA_SUPPORTED = ( Platform.OS === "ios" && majorVersionIOS >= 11 )
+ || ( Platform.OS === "android" && Platform.Version > 21 );
+
+const DROP_SHADOW = getShadow( {
+ offsetHeight: 1,
+ elevation: 1,
+ shadowRadius: 1
+} );
+const GREEN_CIRCLE_CLASS = "bg-inatGreen rounded-full h-[36px] w-[36px] mb-2";
+const ROW_CLASS = "flex-row justify-center space-x-4 w-full flex-1";
+
+const AddObsBottomSheet = ( {
+ closeModal, navAndCloseModal, hidden
+}: Props ) => {
+ const { t } = useTranslation( );
+
+ const prepareObsEdit = useStore( state => state.prepareObsEdit );
+
+ const obsCreateItems = useMemo( ( ) => ( {
+ aiCamera: {
+ text: t( "ID-with-AI-Camera" ),
+ icon: "aicamera",
+ onPress: ( ) => navAndCloseModal( "Camera", { camera: "AI" } ),
+ testID: "aicamera-button",
+ accessibilityLabel: t( "AI-Camera" ),
+ accessibilityHint: t( "Navigates-to-AI-camera" )
+ },
+ standardCamera: {
+ text: t( "Take-photos" ),
+ icon: "camera",
+ onPress: ( ) => navAndCloseModal( "Camera", { camera: "Standard" } ),
+ testID: "camera-button",
+ accessibilityLabel: t( "Camera" ),
+ accessibilityHint: t( "Navigates-to-camera" )
+ },
+ photoLibrary: {
+ text: t( "Upload-photos" ),
+ icon: "photo-library",
+ onPress: ( ) => navAndCloseModal( "PhotoLibrary" ),
+ testID: "import-media-button",
+ accessibilityLabel: t( "Photo-importer" ),
+ accessibilityHint: t( "Navigates-to-photo-importer" )
+ },
+ soundRecorder: {
+ text: t( "Record-a-sound" ),
+ icon: "microphone",
+ onPress: ( ) => navAndCloseModal( "SoundRecorder" ),
+ testID: "record-sound-button",
+ accessibilityLabel: t( "Sound-recorder" ),
+ accessibilityHint: t( "Navigates-to-sound-recorder" )
+ },
+ noEvidence: {
+ text: t( "Create-observation-with-no-evidence" ),
+ icon: "noevidence",
+ onPress: async ( ) => {
+ const newObservation = await Observation.new( );
+ prepareObsEdit( newObservation );
+ navAndCloseModal( "ObsEdit" );
+ },
+ testID: "observe-without-evidence-button",
+ accessibilityLabel: t( "Observation-with-no-evidence" ),
+ accessibilityHint: t( "Navigates-to-observation-edit-screen" )
+ }
+ } ), [
+ navAndCloseModal,
+ prepareObsEdit,
+ t
+ ] );
+
+ const renderAddObsIcon = ( {
+ accessibilityHint,
+ accessibilityLabel,
+ icon,
+ onPress,
+ testID,
+ text
+ }: ObsCreateItem ) => (
+
+
+ {text}
+
+ );
+
+ return (
+
+
+
+ {renderAddObsIcon( obsCreateItems.standardCamera )}
+ {renderAddObsIcon( obsCreateItems.photoLibrary )}
+
+
+ {renderAddObsIcon( obsCreateItems.soundRecorder )}
+ {AI_CAMERA_SUPPORTED && renderAddObsIcon( obsCreateItems.aiCamera )}
+
+
+
+
+ {obsCreateItems.noEvidence.text}
+
+
+
+
+ );
+};
+
+export default AddObsBottomSheet;
diff --git a/src/components/AddObsModal/AddObsButton.js b/src/components/AddObsBottomSheet/AddObsButton.js
similarity index 89%
rename from src/components/AddObsModal/AddObsButton.js
rename to src/components/AddObsBottomSheet/AddObsButton.js
index e4d02ee7e..9c62d3039 100644
--- a/src/components/AddObsModal/AddObsButton.js
+++ b/src/components/AddObsBottomSheet/AddObsButton.js
@@ -1,8 +1,7 @@
// @flow
import { CommonActions, useNavigation } from "@react-navigation/native";
-import AddObsModal from "components/AddObsModal/AddObsModal";
-import { Modal } from "components/SharedComponents";
+import AddObsBottomSheet from "components/AddObsBottomSheet/AddObsBottomSheet";
import GradientButton from "components/SharedComponents/Buttons/GradientButton";
import { t } from "i18next";
import { getCurrentRoute } from "navigation/navigationUtils";
@@ -26,7 +25,6 @@ const AddObsButton = ( ): React.Node => {
// Controls whether to show the tooltip, and to show it only once to the user
const showKey = "AddObsButtonTooltip";
const shownOnce = useStore( state => state.layout.shownOnce );
- const setShownOnce = useStore( state => state.layout.setShownOnce );
const justFinishedSignup = useStore( state => state.layout.justFinishedSignup );
const numOfUserObservations = zustandStorage.getItem( "numOfUserObservations" );
// Base trigger condition in all cases:
@@ -122,30 +120,13 @@ const AddObsButton = ( ): React.Node => {
};
const navToARCamera = ( ) => { navAndCloseModal( "Camera", { camera: "AI" } ); };
- const addObsModal = (
- {
- if ( tooltipIsVisible ) setShownOnce( showKey );
- }}
- />
- );
-
return (
<>
{/* match the animation timing on FadeInView.tsx */}
-
void;
- navAndCloseModal: ( screen: string, params?: {
- camera?: string
- } ) => void;
- tooltipIsVisible: boolean;
- dismissTooltip: () => void;
-}
-
-const majorVersionIOS = parseInt( String( Platform.Version ), 10 );
-const AI_CAMERA_SUPPORTED = ( Platform.OS === "ios" && majorVersionIOS >= 11 )
- || ( Platform.OS === "android" && Platform.Version > 21 );
-
-const GREEN_CIRCLE_CLASS = "bg-inatGreen rounded-full h-[46px] w-[46px]";
-const ROW_CLASS = "flex-row justify-center";
-const MARGINS = AI_CAMERA_SUPPORTED
- ? {
- standardCamera: "mr-[37px] bottom-[1px]",
- photoLibrary: "ml-[37px] bottom-[1px]",
- noEvidence: "mr-[26px]",
- soundRecorder: "ml-[26px]"
- }
- : {
- standardCamera: "mr-[9px]",
- photoLibrary: "ml-[9px]",
- noEvidence: "mr-[20px] bottom-[33px]",
- soundRecorder: "ml-[20px] bottom-[33px]"
- };
-
-const AddObsModal = ( {
- closeModal, navAndCloseModal, tooltipIsVisible, dismissTooltip
-}: Props ) => {
- const { t } = useTranslation( );
-
- const prepareObsEdit = useStore( state => state.prepareObsEdit );
-
- const obsCreateItems = useMemo( ( ) => ( {
- aiCamera: {
- text: t( "Use-iNaturalists-AI-Camera" ),
- icon: "aicamera",
- onPress: ( ) => navAndCloseModal( "Camera", { camera: "AI" } ),
- testID: "aicamera-button",
- className: classnames( GREEN_CIRCLE_CLASS, "absolute bottom-[26px]" ),
- accessibilityLabel: t( "AI-Camera" ),
- accessibilityHint: t( "Navigates-to-AI-camera" )
- },
- standardCamera: {
- text: t( "Take-multiple-photos-of-a-single-organism" ),
- icon: "camera",
- onPress: ( ) => navAndCloseModal( "Camera", { camera: "Standard" } ),
- testID: "camera-button",
- accessibilityLabel: t( "Camera" ),
- accessibilityHint: t( "Navigates-to-camera" ),
- className: classnames( GREEN_CIRCLE_CLASS, MARGINS.standardCamera )
- },
- photoLibrary: {
- text: t( "Upload-photos-from-your-photo-library" ),
- icon: "photo-library",
- onPress: ( ) => navAndCloseModal( "PhotoLibrary" ),
- testID: "import-media-button",
- className: classnames( GREEN_CIRCLE_CLASS, MARGINS.photoLibrary ),
- accessibilityLabel: t( "Photo-importer" ),
- accessibilityHint: t( "Navigates-to-photo-importer" )
- },
- soundRecorder: {
- text: t( "Record-a-sound" ),
- icon: "microphone",
- onPress: ( ) => navAndCloseModal( "SoundRecorder" ),
- testID: "record-sound-button",
- className: classnames( GREEN_CIRCLE_CLASS, MARGINS.soundRecorder ),
- accessibilityLabel: t( "Sound-recorder" ),
- accessibilityHint: t( "Navigates-to-sound-recorder" )
- },
- noEvidence: {
- text: t( "Create-an-observation-evidence" ),
- icon: "noevidence",
- onPress: async ( ) => {
- const newObservation = await Observation.new( );
- prepareObsEdit( newObservation );
- navAndCloseModal( "ObsEdit" );
- },
- testID: "observe-without-evidence-button",
- className: classnames( GREEN_CIRCLE_CLASS, MARGINS.noEvidence ),
- accessibilityLabel: t( "Observation-with-no-evidence" ),
- accessibilityHint: t( "Navigates-to-observation-edit-screen" )
- },
- closeButton: {
- testID: "close-camera-options-button",
- icon: "close",
- className: classnames( GREEN_CIRCLE_CLASS, "h-[69px] w-[69px]" ),
- onPress: closeModal,
- accessibilityLabel: t( "Close" ),
- accessibilityHint: t( "Closes-new-observation-options" )
- }
- } ), [
- closeModal,
- navAndCloseModal,
- prepareObsEdit,
- t
- ] );
-
- const renderAddObsIcon = ( {
- accessibilityHint,
- accessibilityLabel,
- className,
- icon,
- onPress,
- testID
- }: ObsCreateItem ) => (
-
- );
-
- const renderContent = ( ) => {
- if ( tooltipIsVisible ) {
- return (
-
-
- {t( "Press-and-hold-to-view-more-options" )}
-
-
- {}}
- onLongPress={() => dismissTooltip( )}
- accessibilityLabel={t( "Add-observations" )}
- accessibilityHint={t( "Shows-observation-creation-options" )}
- />
-
- );
- }
- return (
- <>
-
-
- {renderAddObsIcon( obsCreateItems.standardCamera )}
- {AI_CAMERA_SUPPORTED && renderAddObsIcon( obsCreateItems.aiCamera )}
- {renderAddObsIcon( obsCreateItems.photoLibrary )}
-
-
- {renderAddObsIcon( obsCreateItems.noEvidence )}
- {renderAddObsIcon( obsCreateItems.closeButton )}
- {renderAddObsIcon( obsCreateItems.soundRecorder )}
-
- >
- );
- };
-
- return (
- <>
-
- { renderContent( ) }
- >
- );
-};
-
-export default AddObsModal;
diff --git a/src/components/AddObsModal/AddObsModalHelp.tsx b/src/components/AddObsModal/AddObsModalHelp.tsx
deleted file mode 100644
index 6e07a3f70..000000000
--- a/src/components/AddObsModal/AddObsModalHelp.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import classnames from "classnames";
-import {
- Body3,
- Heading2,
- INatIcon,
- INatIconButton
-} from "components/SharedComponents";
-import { Pressable, View } from "components/styledComponents";
-import React, { useState } from "react";
-import { useDeviceOrientation, useTranslation } from "sharedHooks";
-import { storage } from "stores/useStore";
-import colors from "styles/tailwindColors";
-
-export type ObsCreateItem = {
- text?: string,
- icon: string,
- onPress: ( ) => void,
- testID: string,
- className: string,
- accessibilityLabel: string,
- accessibilityHint: string
-}
-
-type Props = {
- obsCreateItems: {
- [addType: string]: ObsCreateItem
- }
-};
-
-const HIDE_ADD_OBS_HELP_TEXT = "hideAddObsHelpText";
-
-const AddObsModalHelp = ( {
- obsCreateItems
-}: Props ) => {
- const { t } = useTranslation( );
- const { screenHeight } = useDeviceOrientation( );
- const [hideHelpText, setHideHelpText] = useState( storage.getBoolean( HIDE_ADD_OBS_HELP_TEXT ) );
-
- // targeting iPhone SE, which has height of 667
- const isSmallScreen = screenHeight < 670;
-
- if ( hideHelpText ) return null;
-
- return (
-
-
-
- {t( "Identify-an-organism" )}
-
-
- {
- setHideHelpText( true );
- storage.set( HIDE_ADD_OBS_HELP_TEXT, true );
- }}
- accessibilityLabel={t( "Close" )}
- accessibilityHint={t( "Closes-new-observation-explanation" )}
- />
-
-
-
- {Object.keys( obsCreateItems )
- .filter( k => k !== "closeButton" )
- .map( k => {
- const item = obsCreateItems[k];
- return (
-
-
-
- {item.text}
-
-
- );
- } )}
-
-
- );
-};
-
-export default AddObsModalHelp;
diff --git a/src/components/Developer/UiLibrary/Buttons.js b/src/components/Developer/UiLibrary/Buttons.js
index a8d1833b7..182dd2480 100644
--- a/src/components/Developer/UiLibrary/Buttons.js
+++ b/src/components/Developer/UiLibrary/Buttons.js
@@ -1,4 +1,4 @@
-import AddObsButton from "components/AddObsModal/AddObsButton";
+import AddObsButton from "components/AddObsBottomSheet/AddObsButton";
import {
Body1,
Body2,
diff --git a/src/components/MyObservations/MyObservationsEmptySimple.js b/src/components/MyObservations/MyObservationsEmptySimple.js
index 57b0e2c13..f5036b55e 100644
--- a/src/components/MyObservations/MyObservationsEmptySimple.js
+++ b/src/components/MyObservations/MyObservationsEmptySimple.js
@@ -1,6 +1,6 @@
// @flow
import { useNavigation } from "@react-navigation/native";
-import AddObsModal from "components/AddObsModal/AddObsModal";
+import AddObsBottomSheet from "components/AddObsBottomSheet/AddObsBottomSheet";
import { AccountCreationCard } from "components/OnboardingModal/PivotCards";
import {
HeaderUser,
@@ -8,7 +8,6 @@ import {
ViewWrapper
} from "components/SharedComponents";
import GradientButton from "components/SharedComponents/Buttons/GradientButton";
-import Modal from "components/SharedComponents/Modal";
import {
Pressable, View
} from "components/styledComponents";
@@ -77,15 +76,10 @@ const MyObservationsEmptySimple = ( { currentUser, isConnected, justFinishedSign
/>
- setShowModal( false )}
- modal={(
- setShowModal( false )}
- navAndCloseModal={navAndCloseModal}
- />
- )}
+ hidden={!showModal}
+ navAndCloseModal={navAndCloseModal}
/>
diff --git a/src/components/PhotoSharing.tsx b/src/components/PhotoSharing.tsx
index e14587f87..dd445cd38 100644
--- a/src/components/PhotoSharing.tsx
+++ b/src/components/PhotoSharing.tsx
@@ -63,7 +63,7 @@ const PhotoSharing = ( ) => {
const { data } = item;
// when sharing, we need to reset zustand like we do while
- // navigating through the AddObsModal
+ // navigating through the AddObsBottomSheet
resetObservationFlowSlice( );
const photoUris = data
diff --git a/src/components/SharedComponents/Sheets/BottomSheet.tsx b/src/components/SharedComponents/Sheets/BottomSheet.tsx
index 0e684912f..ff13dcefc 100644
--- a/src/components/SharedComponents/Sheets/BottomSheet.tsx
+++ b/src/components/SharedComponents/Sheets/BottomSheet.tsx
@@ -18,7 +18,10 @@ const { width } = Dimensions.get( "window" );
const marginOnWide = {
marginHorizontal: width > 500
? ( width - 500 ) / 2
- : 0
+ : 0,
+ borderTopLeftRadius: 24,
+ borderTopRightRadius: 24,
+ overflow: "hidden"
};
// eslint-disable-next-line
@@ -29,14 +32,15 @@ interface Props {
hidden?: boolean;
hideCloseButton?: boolean;
headerText?: string;
- onLayout?: Function;
+ onLayout?: ( event: object ) => void;
// Callback when the user presses the close button or backdrop, not whenever the sheet
// closes
- onPressClose?: Function;
+ onPressClose?: () => void;
snapPoints?: Array;
insideModal?: boolean;
keyboardShouldPersistTaps?: string;
testID?: string;
+ additionalClasses?: string;
}
const StandardBottomSheet = ( {
@@ -49,6 +53,7 @@ const StandardBottomSheet = ( {
snapPoints,
insideModal,
keyboardShouldPersistTaps = "never",
+ additionalClasses,
testID
}: Props ): Node => {
if ( snapPoints ) {
@@ -115,21 +120,24 @@ const StandardBottomSheet = ( {
"pt-7",
insets.bottom > 0
? "pb-7"
- : null
+ : null,
+ additionalClasses
)}
onLayout={onLayout}
// Not ideal, but @gorhom/bottom-sheet components don't support
// testID
testID={testID}
>
-
-
- {headerText}
-
-
+ {headerText && (
+
+
+ {headerText}
+
+
+ )}
{children}
{!hideCloseButton && (
Is the evidence enough to confirm this is 0><1>1><0>?<0>
Potential-disagreement-disagree = <0>No, but this is a member of 0><1>1>
Potential-disagreement-unsure = <0>I don't know but I am sure this is 0><1>1>
-Press-and-hold-to-view-more-options = Press and hold to view more options
Previous-observation = Previous observation
# Accessibility label for a button that goes to the previous slide on onboarding cards
Previous-slide = Previous slide
@@ -1210,8 +1206,8 @@ Switches-to-tab = Switches to { $tab } tab.
Sync-observations = Sync observations
Syncing = Syncing...
# Help text for the button that opens the multi-capture camera
-Take-multiple-photos-of-a-single-organism = Take multiple photos of a single organism
Take-photo = Take photo
+Take-photos = Take photos
# label in project requirements
Taxa = Taxa
TAXON = TAXON
@@ -1279,7 +1275,7 @@ Unreviewed-observations-only = Unreviewed observations only
Upload-Complete = Upload Complete
Upload-in-progress = Upload in progress
UPLOAD-NOW = UPLOAD NOW
-Upload-photos-from-your-photo-library = Upload multiple photos from your photo library
+Upload-photos = Upload photos
Upload-Progress = Upload { $uploadProgress } percent complete
UPLOAD-TO-INATURALIST = UPLOAD TO INATURALIST
# Shows the number of observations a user can upload to iNat from my observations page
@@ -1301,7 +1297,6 @@ Uploading-x-of-y-observations =
*[other] Uploading { $currentUploadCount } of { $total } observations
}
Use-iNaturalist-to-identify-any-living-thing = Use iNaturalist to identify any living thing
-Use-iNaturalists-AI-Camera = Use iNaturalist's AI Camera to identify organisms in real time
# Text for a button prompting the user to grant access to location
USE-LOCATION = USE LOCATION
Use-the-devices-other-camera = Use the device's other camera.
diff --git a/src/i18n/l10n/en.ftl.json b/src/i18n/l10n/en.ftl.json
index a4086a9c8..583ccea83 100644
--- a/src/i18n/l10n/en.ftl.json
+++ b/src/i18n/l10n/en.ftl.json
@@ -116,8 +116,6 @@
"Close-search": "Close search",
"Closes-explanation": "Closes explanation",
"Closes-introduction": "Closes introduction",
- "Closes-new-observation-explanation": "Closes new observation explanation.",
- "Closes-new-observation-options": "Closes new observation options.",
"Closes-withdraw-id-sheet": "Closes \"Withdraw ID\" sheet",
"COLLABORATORS": "COLLABORATORS",
"Collection-Project": "Collection Project",
@@ -144,7 +142,7 @@
"Couldnt-create-identification-error": "Couldn't create identification { $error }",
"Couldnt-create-identification-unknown-error": "Couldn't create identification, unknown error.",
"CREATE-AN-ACCOUNT": "CREATE AN ACCOUNT",
- "Create-an-observation-evidence": "Create an observation with no evidence",
+ "Create-observation-with-no-evidence": "Create observation with no evidence",
"DATA-QUALITY": "DATA QUALITY",
"DATA-QUALITY-ASSESSMENT": "DATA QUALITY ASSESSMENT",
"Data-Quality-Assessment": "Data Quality Assessment",
@@ -315,13 +313,13 @@
"Iconic-taxon-name": "Iconic taxon name: { $iconicTaxon }",
"ID-Suggestions": "ID Suggestions",
"ID-WITH-AI": "ID WITH AI",
+ "ID-with-AI-Camera": "ID with AI Camera",
"ID-Withdrawn": "ID Withdrawn",
"IDENTIFICATION": "IDENTIFICATION",
"Identification-options": "Identification options",
"IDENTIFICATIONS-WITHOUT-NUMBER": "{ $count ->\n [one] IDENTIFICATION\n *[other] IDENTIFICATIONS\n}",
"Identifiers": "Identifiers",
"Identifiers-View": "Identifiers View",
- "Identify-an-organism": "Identify an organism",
"Identify-organisms-in-real-time-with-your-camera": "Identify organisms in real time with your camera",
"Identify-species-anywhere": "Identify species anywhere",
"If-an-account-with-that-email-exists": "If an account with that email exists, we've sent password reset instructions to your email.",
@@ -546,7 +544,6 @@
"Potential-disagreement-description": "<0>Is the evidence enough to confirm this is 0><1>1><0>?<0>",
"Potential-disagreement-disagree": "<0>No, but this is a member of 0><1>1>",
"Potential-disagreement-unsure": "<0>I don't know but I am sure this is 0><1>1>",
- "Press-and-hold-to-view-more-options": "Press and hold to view more options",
"Previous-observation": "Previous observation",
"Previous-slide": "Previous slide",
"Privacy-Policy": "Privacy Policy",
@@ -762,8 +759,8 @@
"Switches-to-tab": "Switches to { $tab } tab.",
"Sync-observations": "Sync observations",
"Syncing": "Syncing...",
- "Take-multiple-photos-of-a-single-organism": "Take multiple photos of a single organism",
"Take-photo": "Take photo",
+ "Take-photos": "Take photos",
"Taxa": "Taxa",
"TAXON": "TAXON",
"TAXON-NAMES-DISPLAY": "TAXON NAMES DISPLAY",
@@ -818,7 +815,7 @@
"Upload-Complete": "Upload Complete",
"Upload-in-progress": "Upload in progress",
"UPLOAD-NOW": "UPLOAD NOW",
- "Upload-photos-from-your-photo-library": "Upload multiple photos from your photo library",
+ "Upload-photos": "Upload photos",
"Upload-Progress": "Upload { $uploadProgress } percent complete",
"UPLOAD-TO-INATURALIST": "UPLOAD TO INATURALIST",
"Upload-x-observations": "Upload { $count ->\n [one] 1 observation\n *[other] { $count } observations\n}",
@@ -827,7 +824,6 @@
"Uploading-x-of-y": "Uploading { $currentUploadCount } of { $total }",
"Uploading-x-of-y-observations": "{ $total ->\n [one] Uploading { $currentUploadCount } observation\n *[other] Uploading { $currentUploadCount } of { $total } observations\n}",
"Use-iNaturalist-to-identify-any-living-thing": "Use iNaturalist to identify any living thing",
- "Use-iNaturalists-AI-Camera": "Use iNaturalist's AI Camera to identify organisms in real time",
"USE-LOCATION": "USE LOCATION",
"Use-the-devices-other-camera": "Use the device's other camera.",
"Use-the-iNaturalist-camera-to-see-real-time-identifications-and-take-photos": "Use the iNaturalist camera to see real-time identifications and take photos!",
diff --git a/src/i18n/strings.ftl b/src/i18n/strings.ftl
index 198c98212..eafd9cd18 100644
--- a/src/i18n/strings.ftl
+++ b/src/i18n/strings.ftl
@@ -228,9 +228,6 @@ Closes-explanation = Closes explanation
# appear when you first install the app
Closes-introduction = Closes introduction
# Accessibility hint for button that closes the help that
-# appears when you start a new observation for the first time
-Closes-new-observation-explanation = Closes new observation explanation.
-Closes-new-observation-options = Closes new observation options.
Closes-withdraw-id-sheet = Closes "Withdraw ID" sheet
# Heading for a section that describes people and organizations that
# collaborate with iNaturalist
@@ -274,7 +271,7 @@ Couldnt-create-comment = Couldn't create comment
Couldnt-create-identification-error = Couldn't create identification { $error }
Couldnt-create-identification-unknown-error = Couldn't create identification, unknown error.
CREATE-AN-ACCOUNT = CREATE AN ACCOUNT
-Create-an-observation-evidence = Create an observation with no evidence
+Create-observation-with-no-evidence = Create observation with no evidence
DATA-QUALITY = DATA QUALITY
DATA-QUALITY-ASSESSMENT = DATA QUALITY ASSESSMENT
# Label for button that navigates users to the data quality screen
@@ -563,6 +560,7 @@ Iconic-taxon-name = Iconic taxon name: { $iconicTaxon }
ID-Suggestions = ID Suggestions
# Short for: Identify with AI. Label for a button that will load identifications for a given photo/sound
ID-WITH-AI = ID WITH AI
+ID-with-AI-Camera = ID with AI Camera
# Identification Status
ID-Withdrawn = ID Withdrawn
IDENTIFICATION = IDENTIFICATION
@@ -575,7 +573,6 @@ IDENTIFICATIONS-WITHOUT-NUMBER =
}
Identifiers = Identifiers
Identifiers-View = Identifiers View
-Identify-an-organism = Identify an organism
# Title of screen asking for permission to access the camera
Identify-organisms-in-real-time-with-your-camera = Identify organisms in real time with your camera
# Onboarding slides
@@ -925,7 +922,6 @@ POTENTIAL-DISAGREEMENT = POTENTIAL DISAGREEMENT
Potential-disagreement-description = <0>Is the evidence enough to confirm this is 0><1>1><0>?<0>
Potential-disagreement-disagree = <0>No, but this is a member of 0><1>1>
Potential-disagreement-unsure = <0>I don't know but I am sure this is 0><1>1>
-Press-and-hold-to-view-more-options = Press and hold to view more options
Previous-observation = Previous observation
# Accessibility label for a button that goes to the previous slide on onboarding cards
Previous-slide = Previous slide
@@ -1210,8 +1206,8 @@ Switches-to-tab = Switches to { $tab } tab.
Sync-observations = Sync observations
Syncing = Syncing...
# Help text for the button that opens the multi-capture camera
-Take-multiple-photos-of-a-single-organism = Take multiple photos of a single organism
Take-photo = Take photo
+Take-photos = Take photos
# label in project requirements
Taxa = Taxa
TAXON = TAXON
@@ -1279,7 +1275,7 @@ Unreviewed-observations-only = Unreviewed observations only
Upload-Complete = Upload Complete
Upload-in-progress = Upload in progress
UPLOAD-NOW = UPLOAD NOW
-Upload-photos-from-your-photo-library = Upload multiple photos from your photo library
+Upload-photos = Upload photos
Upload-Progress = Upload { $uploadProgress } percent complete
UPLOAD-TO-INATURALIST = UPLOAD TO INATURALIST
# Shows the number of observations a user can upload to iNat from my observations page
@@ -1301,7 +1297,6 @@ Uploading-x-of-y-observations =
*[other] Uploading { $currentUploadCount } of { $total } observations
}
Use-iNaturalist-to-identify-any-living-thing = Use iNaturalist to identify any living thing
-Use-iNaturalists-AI-Camera = Use iNaturalist's AI Camera to identify organisms in real time
# Text for a button prompting the user to grant access to location
USE-LOCATION = USE LOCATION
Use-the-devices-other-camera = Use the device's other camera.
diff --git a/src/navigation/BottomTabNavigator/CustomTabBar.js b/src/navigation/BottomTabNavigator/CustomTabBar.js
index 18fa791f8..ea48d858d 100644
--- a/src/navigation/BottomTabNavigator/CustomTabBar.js
+++ b/src/navigation/BottomTabNavigator/CustomTabBar.js
@@ -1,6 +1,6 @@
// @flow
import classNames from "classnames";
-import AddObsButton from "components/AddObsModal/AddObsButton";
+import AddObsButton from "components/AddObsBottomSheet/AddObsButton";
import { View } from "components/styledComponents";
import type { Node } from "react";
import React from "react";
diff --git a/tests/integration/navigation/AddObsButton.test.js b/tests/integration/navigation/AddObsButton.test.js
index 5c11f6b9c..35550a96f 100644
--- a/tests/integration/navigation/AddObsButton.test.js
+++ b/tests/integration/navigation/AddObsButton.test.js
@@ -1,5 +1,5 @@
import { screen, userEvent } from "@testing-library/react-native";
-import AddObsButton from "components/AddObsModal/AddObsButton";
+import AddObsButton from "components/AddObsBottomSheet/AddObsButton";
import i18next from "i18next";
import React from "react";
import { renderComponent } from "tests/helpers/render";
@@ -48,8 +48,8 @@ const longPress = async ( ) => {
};
const showNoEvidenceOption = ( ) => {
- const noEvidenceButton = screen.getByLabelText(
- i18next.t( "Observation-with-no-evidence" )
+ const noEvidenceButton = screen.getByTestId(
+ i18next.t( "observe-without-evidence-button" )
);
expect( noEvidenceButton ).toBeTruthy( );
return noEvidenceButton;
@@ -87,7 +87,7 @@ describe( "with advanced user layout", ( ) => {
} );
} );
- it( "opens AddObsModal", async ( ) => {
+ it( "opens AddObsBottomSheet", async ( ) => {
renderComponent( );
await regularPress( );
showNoEvidenceOption( );
diff --git a/tests/unit/components/AddObsModal/AddObsButton.test.js b/tests/unit/components/AddObsModal/AddObsButton.test.js
index 212e29dad..3f8ed154c 100644
--- a/tests/unit/components/AddObsModal/AddObsButton.test.js
+++ b/tests/unit/components/AddObsModal/AddObsButton.test.js
@@ -1,11 +1,7 @@
import { screen } from "@testing-library/react-native";
-import AddObsButton from "components/AddObsModal/AddObsButton";
+import AddObsButton from "components/AddObsBottomSheet/AddObsButton";
import React from "react";
-import * as useCurrentUser from "sharedHooks/useCurrentUser";
-import { zustandStorage } from "stores/useStore";
-import factory from "tests/factory";
import { renderComponent } from "tests/helpers/render";
-import setStoreStateLayout from "tests/helpers/setStoreStateLayout";
// Mock getCurrentRoute to return ObsList
jest.mock( "navigation/navigationUtils", () => ( {
@@ -14,8 +10,6 @@ jest.mock( "navigation/navigationUtils", () => ( {
} )
} ) );
-const mockUser = factory( "LocalUser" );
-
jest.mock( "sharedHooks/useCurrentUser", () => ( {
__esModule: true,
default: () => undefined
@@ -34,88 +28,4 @@ describe( "AddObsButton", () => {
// Snapshot test
expect( screen ).toMatchSnapshot();
} );
-
- it( "does not render tooltip in default state", () => {
- renderComponent( );
-
- const tooltipText = screen.queryByText(
- "Press and hold to view more options"
- );
- expect( tooltipText ).toBeFalsy();
- } );
-} );
-
-describe( "shows tooltip", () => {
- it( "to logged out users with 2 observations", async () => {
- zustandStorage.setItem( "numOfUserObservations", 2 );
-
- renderComponent( );
-
- const tooltipText = await screen.findByText(
- "Press and hold to view more options"
- );
- expect( tooltipText ).toBeTruthy();
- } );
-
- it( "to logged in users with less than 50 observations", async () => {
- zustandStorage.setItem( "numOfUserObservations", 2 );
- jest.spyOn( useCurrentUser, "default" ).mockImplementation( () => mockUser );
-
- renderComponent( );
-
- // Temporarily disabled the tooltip for new users, as it is freezing the app in some cases.
- // const tooltipText = await screen.findByText(
- // "Press and hold to view more options"
- // );
- // expect( tooltipText ).toBeTruthy();
- } );
-
- it( "to new users only after they dismissed the account creation card", async () => {
- zustandStorage.setItem( "numOfUserObservations", 1 );
- setStoreStateLayout( {
- justFinishedSignup: true
- } );
-
- renderComponent( );
-
- const tooltipText = screen.queryByText(
- "Press and hold to view more options"
- );
- expect( tooltipText ).toBeFalsy();
-
- setStoreStateLayout( {
- shownOnce: {
- "account-creation": true
- }
- } );
-
- // Temporarily disabled the tooltip for new users, as it is freezing the app in some cases.
- // const tooltipTextAfter = await screen.findByText(
- // "Press and hold to view more options"
- // );
- // expect( tooltipTextAfter ).toBeTruthy();
- } );
-
- it( "to logged in users with more than 50 observations after card dismissal", async () => {
- zustandStorage.setItem( "numOfUserObservations", 51 );
-
- renderComponent( );
-
- const tooltipText = screen.queryByText(
- "Press and hold to view more options"
- );
- expect( tooltipText ).toBeFalsy();
-
- setStoreStateLayout( {
- shownOnce: {
- "fifty-observation": true
- }
- } );
-
- // Temporarily disabled the tooltip for new users, as it is freezing the app in some cases.
- // const tooltipTextAfter = await screen.findByText(
- // "Press and hold to view more options"
- // );
- // expect( tooltipTextAfter ).toBeTruthy();
- } );
} );
diff --git a/tests/unit/components/AddObsModal/AddObsModal.test.js b/tests/unit/components/AddObsModal/AddObsModal.test.js
index 9108fd880..8d5a66d4d 100644
--- a/tests/unit/components/AddObsModal/AddObsModal.test.js
+++ b/tests/unit/components/AddObsModal/AddObsModal.test.js
@@ -1,6 +1,5 @@
import { render, screen } from "@testing-library/react-native";
-import AddObsModal from "components/AddObsModal/AddObsModal";
-import i18next from "i18next";
+import AddObsBottomSheet from "components/AddObsBottomSheet/AddObsBottomSheet";
import React from "react";
// Make sure the mock is using a recent-ish version
@@ -13,11 +12,11 @@ jest.mock( "react-native/Libraries/Utilities/Platform", ( ) => ( {
}
} ) );
-describe( "AddObsModal", ( ) => {
+describe( "AddObsBottomSheet", ( ) => {
it( "shows the AI camera button", async ( ) => {
- render( );
- const aiCameraButton = screen.getByLabelText(
- i18next.t( "AI-Camera" )
+ render( );
+ const aiCameraButton = screen.getByTestId(
+ "aicamera-button"
);
expect( aiCameraButton ).toBeOnTheScreen();
} );
diff --git a/tests/unit/components/AddObsModal/AddObsModalIOS9.test.js b/tests/unit/components/AddObsModal/AddObsModalIOS9.test.js
index 293b9cf0a..255634e10 100644
--- a/tests/unit/components/AddObsModal/AddObsModalIOS9.test.js
+++ b/tests/unit/components/AddObsModal/AddObsModalIOS9.test.js
@@ -1,8 +1,8 @@
-// Separate tests for iOS 9. AddObsModal sets some OS-specific constants at
+// Separate tests for iOS 9. AddObsBottomSheet sets some OS-specific constants at
// load time that can't be altered at runtime, so we're using a separate test
// with a separate mock to control those load time values.
import { render, screen } from "@testing-library/react-native";
-import AddObsModal from "components/AddObsModal/AddObsModal";
+import AddObsBottomSheet from "components/AddObsBottomSheet/AddObsBottomSheet";
import i18next from "i18next";
import React from "react";
@@ -16,9 +16,9 @@ jest.mock( "react-native/Libraries/Utilities/Platform", () => ( {
}
} ) );
-describe( "AddObsModal in iOS 9", ( ) => {
+describe( "AddObsBottomSheet in iOS 9", ( ) => {
it( "hides AI camera button on older devices", async ( ) => {
- render( );
+ render( );
const arCameraButton = screen.queryByLabelText(
i18next.t( "AI-Camera" )
);