Skip to content

Commit

Permalink
266 flash icon change (inaturalist#271)
Browse files Browse the repository at this point in the history
* Add script to clean start
* Add function to camera mock
* Basic StandardCamera test setup
* Display flash off icon in camera
* Add accessibility labels to strings
* Change to use testID for tests
* Rename package script
* Update vision-camera mock
  • Loading branch information
jtklein authored Dec 13, 2022
1 parent da9cd48 commit 7324117
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"clean-start": "npx react-native clean-project-auto && npx pod-install && npm start",
"test": "jest",
"lint": "npm run lint:eslint && npm run lint:flow",
"lint:eslint": "eslint . --fix",
Expand Down
45 changes: 36 additions & 9 deletions src/components/Camera/StandardCamera.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export const MAX_PHOTOS_ALLOWED = 20;
const StandardCamera = ( ): Node => {
const {
addCameraPhotosToCurrentObservation,
createObsWithCameraPhotos, cameraPreviewUris, setCameraPreviewUris, allObsPhotoUris,
createObsWithCameraPhotos,
cameraPreviewUris,
setCameraPreviewUris,
allObsPhotoUris,
evidenceToAdd,
setEvidenceToAdd
} = useContext( ObsEditContext );
Expand Down Expand Up @@ -89,13 +92,35 @@ const StandardCamera = ( ): Node => {
navigation.navigate( "ObsEdit" );
};

const renderCameraOptionsButtons = icon => (
<Avatar.Icon
size={40}
icon={icon}
style={{ backgroundColor: colors.gray }}
/>
);
const renderCameraOptionsButtons = icon => {
let testID = "";
let accessibilityLabel = "";
switch ( icon ) {
case "flash":
testID = "flash-button-label-flash";
accessibilityLabel = t( "flash-button-label-flash" );
break;
case "flash-off":
testID = "flash-button-label-flash-off";
accessibilityLabel = t( "flash-button-label-flash-off" );
break;
case "camera-flip":
testID = "camera-button-label-switch-camera";
accessibilityLabel = t( "camera-button-label-switch-camera" );
break;
default:
break;
}
return (
<Avatar.Icon
testID={testID}
accessibilityLabel={accessibilityLabel}
size={40}
icon={icon}
style={{ backgroundColor: colors.gray }}
/>
);
};

const renderCameraButton = ( icon, disabled ) => (
<Avatar.Icon
Expand All @@ -119,7 +144,9 @@ const StandardCamera = ( ): Node => {
<View className="flex-row justify-between w-screen mb-4 px-4">
{hasFlash ? (
<Pressable onPress={toggleFlash}>
{renderCameraOptionsButtons( "flash" )}
{takePhotoOptions.flash === "on"
? renderCameraOptionsButtons( "flash" )
: renderCameraOptionsButtons( "flash-off" )}
</Pressable>
) : <View />}
<Pressable onPress={flipCamera}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Identify/GridItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const GridItem = ( {
]}
testID={`ObsList.gridItem.${item.uuid}`}
accessibilityRole="link"
accessibilityLabel="Navigate to observation details screen"
accessibilityLabel={t( "Navigate-to-observation-details" )}
>
<Image
source={imageUri}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ObsDetails/ActivityItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ const ActivityItem = ( {
className="flex-row my-3 ml-3 items-center"
onPress={navToTaxonDetails}
accessibilityRole="link"
accessibilityLabel="go to taxon details"
accessibilityLabel={t( "Navigate-to-taxon-details" )}
>
<SmallSquareImage uri={Taxon.uri( taxon )} />
<View>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ObsDetails/ObsDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ const ObsDetails = ( ): Node => {
onPress={navToTaxonDetails}
testID={`ObsDetails.taxon.${taxon.id}`}
accessibilityRole="link"
accessibilityLabel="go to taxon details"
accessibilityLabel={t( "Navigate-to-taxon-details" )}
>
<Text>
{checkCamelAndSnakeCase( taxon, "preferredCommonName" )}
Expand Down
3 changes: 2 additions & 1 deletion src/components/Observations/GridItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import {
Image, Pressable, View
} from "components/styledComponents";
import { t } from "i18next";
import type { Node } from "react";
import React from "react";
import IconMaterial from "react-native-vector-icons/MaterialIcons";
Expand Down Expand Up @@ -51,7 +52,7 @@ const GridItem = ( {
className={`w-1/2 px-4 py-2 ${( index || 0 ) % ( numColumns || 2 ) === 0 ? "pr-2" : "pl-2"}`}
testID={`ObsList.gridItem.${item.uuid}`}
accessibilityRole="link"
accessibilityLabel="Navigate to observation details screen"
accessibilityLabel={t( "Navigate-to-observation-details" )}
>
<View>
{
Expand Down
3 changes: 2 additions & 1 deletion src/components/Observations/ObsCard.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow

import { Image, Pressable, View } from "components/styledComponents";
import { t } from "i18next";
import { RealmContext } from "providers/contexts";
import type { Node } from "react";
import React, { useEffect, useState } from "react";
Expand Down Expand Up @@ -50,7 +51,7 @@ const ObsCard = ( { item, handlePress }: Props ): Node => {
className="flex-row my-2 mx-3 justify-between"
testID={`ObsList.obsCard.${item.uuid}`}
accessibilityRole="link"
accessibilityLabel="Navigate to observation details screen"
accessibilityLabel={t( "Navigate-to-observation-details" )}
>
<View className="flex-row shrink">
{obsListPhoto}
Expand Down
13 changes: 13 additions & 0 deletions src/i18n/l10n/en.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ Blocked-Users = Blocked Users
# Quality grade option: Casual (shortened for My Observations view)
C = C
# Accessible label for the camera button
camera-button-label-switch-camera = Use the device's other camera.
Camera-Roll = Camera Roll
Cancel = Cancel
Expand Down Expand Up @@ -146,6 +149,12 @@ Finish = Finish
Fish = Fish
# Accessible label for the flash button, when flas is turned on
flash-button-label-flash = The flash is turned on. Press here to disable it.
# Accessible label for the flash button, when flas is turned off
flash-button-label-flash-off = The flash is turned off. Press here to enable it.
Following = Following
# Forgot password link
Expand Down Expand Up @@ -276,6 +285,10 @@ Native = Native
Navigate-to-login-screen = Navigate to login screen
Navigate-to-observation-details = Navigate to observation details screen
Navigate-to-taxon-details = Navigate to taxon details
# Header for nearby projects
Nearby = Nearby
Expand Down
14 changes: 14 additions & 0 deletions src/i18n/l10n/en.ftl.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
"comment": "Quality grade option: Casual (shortened for My Observations view)",
"val": "C"
},
"camera-button-label-switch-camera": {
"comment": "Accessible label for the camera button",
"val": "Use the device's other camera."
},
"Camera-Roll": "Camera Roll",
"Cancel": "Cancel",
"Captive-Cultivated": "Captive/Cultivated",
Expand Down Expand Up @@ -98,6 +102,14 @@
"Filters": "Filters",
"Finish": "Finish",
"Fish": "Fish",
"flash-button-label-flash": {
"comment": "Accessible label for the flash button, when flas is turned on",
"val": "The flash is turned on. Press here to disable it."
},
"flash-button-label-flash-off": {
"comment": "Accessible label for the flash button, when flas is turned off",
"val": "The flash is turned off. Press here to enable it."
},
"Following": "Following",
"Forgot-Password": {
"comment": "Forgot password link",
Expand Down Expand Up @@ -187,6 +199,8 @@
"Names": "Names",
"Native": "Native",
"Navigate-to-login-screen": "Navigate to login screen",
"Navigate-to-observation-details": "Navigate to observation details screen",
"Navigate-to-taxon-details": "Navigate to taxon details",
"Nearby": {
"comment": "Header for nearby projects",
"val": "Nearby"
Expand Down
13 changes: 13 additions & 0 deletions src/i18n/strings.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ Blocked-Users = Blocked Users
# Quality grade option: Casual (shortened for My Observations view)
C = C
# Accessible label for the camera button
camera-button-label-switch-camera = Use the device's other camera.
Camera-Roll = Camera Roll
Cancel = Cancel
Expand Down Expand Up @@ -146,6 +149,12 @@ Finish = Finish
Fish = Fish
# Accessible label for the flash button, when flas is turned on
flash-button-label-flash = The flash is turned on. Press here to disable it.
# Accessible label for the flash button, when flas is turned off
flash-button-label-flash-off = The flash is turned off. Press here to enable it.
Following = Following
# Forgot password link
Expand Down Expand Up @@ -276,6 +285,10 @@ Native = Native
Navigate-to-login-screen = Navigate to login screen
Navigate-to-observation-details = Navigate to observation details screen
Navigate-to-taxon-details = Navigate to taxon details
# Header for nearby projects
Nearby = Nearby
Expand Down
9 changes: 7 additions & 2 deletions tests/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import mockRNLocalize from "react-native-localize/mock";
import mockSafeAreaContext from "react-native-safe-area-context/jest/mock";

import { makeResponse } from "./factory";
import { mockCamera, mockSortDevices } from "./vision-camera/vision-camera";
import {
mockCamera,
mockSortDevices,
mockUseCameraDevices
} from "./vision-camera/vision-camera";

jest.mock(
"@react-native-async-storage/async-storage",
Expand All @@ -21,7 +25,8 @@ require( "react-native-reanimated/lib/reanimated2/jestUtils" ).setUpTests();

jest.mock( "react-native-vision-camera", ( ) => ( {
Camera: mockCamera,
sortDevices: mockSortDevices
sortDevices: mockSortDevices,
useCameraDevices: mockUseCameraDevices
} ) );

jest.mock( "react-native-localize", () => mockRNLocalize );
Expand Down
65 changes: 65 additions & 0 deletions tests/unit/components/Camera/StandardCamera.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { fireEvent, render, screen } from "@testing-library/react-native";
import StandardCamera from "components/Camera/StandardCamera";
import { ObsEditContext } from "providers/contexts";
import React from "react";
import { View } from "react-native";

const mockedNavigate = jest.fn();

jest.mock( "@react-navigation/native", () => {
const actualNav = jest.requireActual( "@react-navigation/native" );
return {
...actualNav,
useNavigation: () => ( {
navigate: mockedNavigate
} ),
useRoute: () => ( {} )
};
} );

const mockValue = {
addCameraPhotosToCurrentObservation: jest.fn(),
allObsPhotoUris: [],
cameraPreviewUris: []
};

const mockView = <View />;
jest.mock( "components/Camera/CameraView", () => ( {
__esModule: true,
default: ( ) => mockView
} ) );

jest.mock( "components/Camera/FadeInOutView", () => ( {
__esModule: true,
default: () => mockView
} ) );

jest.mock( "components/Camera/PhotoPreview", () => ( {
__esModule: true,
default: () => mockView
} ) );

const renderStandardCamera = () => render(
<ObsEditContext.Provider value={mockValue}>
<StandardCamera />
</ObsEditContext.Provider>
);

describe( "StandardCamera", ( ) => {
test( "should first render with flash disabled", async () => {
renderStandardCamera();

await screen.findByTestId( "flash-button-label-flash-off" );
} );

test( "should change to flash enabled on button press", async () => {
renderStandardCamera();

const flashButton = await screen.findByTestId(
"flash-button-label-flash-off"
);
fireEvent.press( flashButton );

await screen.findByTestId( "flash-button-label-flash" );
} );
} );
27 changes: 27 additions & 0 deletions tests/vision-camera/vision-camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,30 @@ export class mockCamera extends React.PureComponent {
}

export const mockSortDevices = ( _left, _right ) => 1;

export const mockUseCameraDevices = _deviceType => {
const devices = {
back: {
position: "back",
hasFlash: true
},
front: {
devices: ["wide-angle-camera"],
hasFlash: true,
hasTorch: true,
id: "1",
isMultiCam: true,
maxZoom: 12.931958198547363,
minZoom: 1,
name: "front (1)",
neutralZoom: 1,
position: "front",
supportsDepthCapture: false,
supportsFocus: true,
supportsLowLightBoost: false,
supportsParallelVideoProcessing: true,
supportsRawCapture: true
}
};
return devices;
};

0 comments on commit 7324117

Please sign in to comment.