mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2025-12-23 22:18:36 -05:00
Add functionality for advanced iNaturalist mode (#2591)
* Add functionality for advanced iNaturalist mode * Fix language settings test by toggling advanced mode on * Fix e2e tests by adding advanced user toggle * Fix more tests in Settings with advanced toggle
This commit is contained in:
committed by
GitHub
parent
31ce8994d9
commit
1c59f89a14
@@ -10,6 +10,10 @@ export default async function switchPowerMode() {
|
||||
const settingsDrawerMenuItem = element( by.id( "settings" ) );
|
||||
await waitFor( settingsDrawerMenuItem ).toBeVisible().withTimeout( 10000 );
|
||||
await settingsDrawerMenuItem.tap();
|
||||
// Tap the settings radio button for advanced interface mode
|
||||
const advancedInterfaceRadioButton = element( by.id( "advanced-interface-option" ) );
|
||||
await waitFor( advancedInterfaceRadioButton ).toBeVisible().withTimeout( 10000 );
|
||||
await advancedInterfaceRadioButton.tap();
|
||||
// Tap the settings radio button for power user mode
|
||||
const powerUserRadioButton = element( by.id( "all-observation-option" ) );
|
||||
await waitFor( powerUserRadioButton ).toBeVisible().withTimeout( 10000 );
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
Heading4,
|
||||
PickerSheet
|
||||
} from "components/SharedComponents";
|
||||
import { View } from "components/styledComponents";
|
||||
import _ from "lodash";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import changeLanguage from "sharedHelpers/changeLanguage.ts";
|
||||
@@ -51,8 +52,8 @@ const LanguageSetting = ( { onChange }: Props ) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading4 className="mt-7">{t( "APP-LANGUAGE" )}</Heading4>
|
||||
<View className="mb-9">
|
||||
<Heading4>{t( "APP-LANGUAGE" )}</Heading4>
|
||||
<Button
|
||||
className="mt-4"
|
||||
text={t( "CHANGE-APP-LANGUAGE" )}
|
||||
@@ -75,7 +76,7 @@ const LanguageSetting = ( { onChange }: Props ) => {
|
||||
pickerValues={webLocalesOptions}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -145,16 +145,9 @@ const Settings = ( ) => {
|
||||
updateUserMutation.mutate( payload );
|
||||
}, [settings?.id, updateUserMutation] );
|
||||
|
||||
const renderLoggedIn = ( ) => (
|
||||
<View>
|
||||
{( isSaving || isLoading ) && (
|
||||
<View className="absolute z-10 bg-white/80
|
||||
w-full h-full flex items-center justify-center"
|
||||
>
|
||||
<ActivityIndicator size={50} />
|
||||
</View>
|
||||
)}
|
||||
<Heading4 className="mt-7">{t( "TAXON-NAMES-DISPLAY" )}</Heading4>
|
||||
const renderTaxonNamesSection = ( ) => (
|
||||
<View className="mb-9">
|
||||
<Heading4>{t( "TAXON-NAMES-DISPLAY" )}</Heading4>
|
||||
<Body2 className="mt-3">{t( "This-is-how-taxon-names-will-be-displayed" )}</Body2>
|
||||
<View className="mt-[22px]">
|
||||
<RadioButtonRow
|
||||
@@ -180,6 +173,19 @@ const Settings = ( ) => {
|
||||
label={t( "Scientific-Name" )}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const renderLoggedIn = ( ) => (
|
||||
<View>
|
||||
{( isSaving || isLoading ) && (
|
||||
<View className="absolute z-10 bg-white/80
|
||||
w-full h-full flex items-center justify-center"
|
||||
>
|
||||
<ActivityIndicator size={50} />
|
||||
</View>
|
||||
)}
|
||||
{!isDefaultMode && renderTaxonNamesSection( )}
|
||||
<LanguageSetting
|
||||
onChange={newLocale => {
|
||||
QueueItem.enqueue(
|
||||
@@ -194,46 +200,48 @@ const Settings = ( ) => {
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Heading4 className="mt-7">{t( "INATURALIST-ACCOUNT-SETTINGS" )}</Heading4>
|
||||
<Body2 className="mt-2">{t( "Edit-your-profile-change-your-settings" )}</Body2>
|
||||
<Button
|
||||
className="mt-4"
|
||||
text={t( "ACCOUNT-SETTINGS" )}
|
||||
onPress={() => {
|
||||
confirmInternetConnection( );
|
||||
if ( !isConnected ) { return; }
|
||||
setShowingWebViewSettings( true );
|
||||
<View>
|
||||
<Heading4>{t( "INATURALIST-ACCOUNT-SETTINGS" )}</Heading4>
|
||||
<Body2 className="mt-2">{t( "Edit-your-profile-change-your-settings" )}</Body2>
|
||||
<Button
|
||||
className="mt-4"
|
||||
text={t( "ACCOUNT-SETTINGS" )}
|
||||
onPress={() => {
|
||||
confirmInternetConnection( );
|
||||
if ( !isConnected ) { return; }
|
||||
setShowingWebViewSettings( true );
|
||||
|
||||
navigation.navigate( "FullPageWebView", {
|
||||
title: t( "ACCOUNT-SETTINGS" ),
|
||||
loggedIn: true,
|
||||
initialUrl: SETTINGS_URL,
|
||||
blurEvent: FINISHED_WEB_SETTINGS,
|
||||
clickablePathnames: ["/users/delete"],
|
||||
skipSetSourceInShouldStartLoadWithRequest: true,
|
||||
shouldLoadUrl: url => {
|
||||
async function signOutGoHome() {
|
||||
Alert.alert(
|
||||
t( "Account-Deleted" ),
|
||||
t( "It-may-take-up-to-an-hour-to-remove-content" )
|
||||
);
|
||||
// sign out
|
||||
await signOut( { realm, clearRealm: true, queryClient } );
|
||||
// navigate to My Obs
|
||||
navigation.navigate( "ObsList" );
|
||||
navigation.navigate( "FullPageWebView", {
|
||||
title: t( "ACCOUNT-SETTINGS" ),
|
||||
loggedIn: true,
|
||||
initialUrl: SETTINGS_URL,
|
||||
blurEvent: FINISHED_WEB_SETTINGS,
|
||||
clickablePathnames: ["/users/delete"],
|
||||
skipSetSourceInShouldStartLoadWithRequest: true,
|
||||
shouldLoadUrl: url => {
|
||||
async function signOutGoHome() {
|
||||
Alert.alert(
|
||||
t( "Account-Deleted" ),
|
||||
t( "It-may-take-up-to-an-hour-to-remove-content" )
|
||||
);
|
||||
// sign out
|
||||
await signOut( { realm, clearRealm: true, queryClient } );
|
||||
// navigate to My Obs
|
||||
navigation.navigate( "ObsList" );
|
||||
}
|
||||
// If the webview navigates to a URL that indicates the account
|
||||
// was deleted, sign the current user out of the app
|
||||
if ( url === `${Config.OAUTH_API_URL}/?account_deleted=true` ) {
|
||||
signOutGoHome( );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// If the webview navigates to a URL that indicates the account
|
||||
// was deleted, sign the current user out of the app
|
||||
if ( url === `${Config.OAUTH_API_URL}/?account_deleted=true` ) {
|
||||
signOutGoHome( );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} );
|
||||
}}
|
||||
accessibilityLabel={t( "INATURALIST-SETTINGS" )}
|
||||
/>
|
||||
} );
|
||||
}}
|
||||
accessibilityLabel={t( "INATURALIST-SETTINGS" )}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -241,9 +249,9 @@ const Settings = ( ) => {
|
||||
<ScrollViewWrapper>
|
||||
<StatusBar barStyle="dark-content" />
|
||||
<View className="p-5">
|
||||
<View className="mb-5">
|
||||
<Heading4>{t( "INATURALIST-INTERFACE-MODE" )}</Heading4>
|
||||
<View className="mt-[22px] pr-5">
|
||||
<View className="mb-9">
|
||||
<Heading4>{t( "INATURALIST-MODE" )}</Heading4>
|
||||
<View className="mt-[22px]">
|
||||
<RadioButtonRow
|
||||
smallLabel
|
||||
checked={isDefaultMode}
|
||||
@@ -251,36 +259,39 @@ const Settings = ( ) => {
|
||||
label={t( "Default--interface-mode" )}
|
||||
/>
|
||||
</View>
|
||||
<View className="mt-4 pr-5">
|
||||
<View className="mt-4">
|
||||
<RadioButtonRow
|
||||
testID="advanced-interface-option"
|
||||
smallLabel
|
||||
checked={!isDefaultMode}
|
||||
onPress={( ) => setIsDefaultMode( false )}
|
||||
label={t( "Advanced--interface-mode" )}
|
||||
label={t( "Advanced--interface-mode-with-explainer" )}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View className="mb-5">
|
||||
<Heading4>{t( "OBSERVATION-BUTTON" )}</Heading4>
|
||||
<Body2 className="mt-3">{t( "When-tapping-the-green-observation-button" )}</Body2>
|
||||
<View className="mt-[22px] pr-5">
|
||||
<RadioButtonRow
|
||||
smallLabel
|
||||
checked={!isAllAddObsOptionsMode}
|
||||
onPress={() => setIsAllAddObsOptionsMode( false )}
|
||||
label={t( "iNaturalist-AI-Camera" )}
|
||||
/>
|
||||
{!isDefaultMode && (
|
||||
<View className="mb-9">
|
||||
<Heading4>{t( "OBSERVATION-BUTTON" )}</Heading4>
|
||||
<Body2 className="mt-3">{t( "When-tapping-the-green-observation-button" )}</Body2>
|
||||
<View className="mt-[22px] pr-5">
|
||||
<RadioButtonRow
|
||||
smallLabel
|
||||
checked={!isAllAddObsOptionsMode}
|
||||
onPress={() => setIsAllAddObsOptionsMode( false )}
|
||||
label={t( "iNaturalist-AI-Camera" )}
|
||||
/>
|
||||
</View>
|
||||
<View className="mt-4 pr-5">
|
||||
<RadioButtonRow
|
||||
testID="all-observation-option"
|
||||
smallLabel
|
||||
checked={isAllAddObsOptionsMode}
|
||||
onPress={() => setIsAllAddObsOptionsMode( true )}
|
||||
label={t( "All-observation-option" )}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View className="mt-4 pr-5">
|
||||
<RadioButtonRow
|
||||
testID="all-observation-option"
|
||||
smallLabel
|
||||
checked={isAllAddObsOptionsMode}
|
||||
onPress={() => setIsAllAddObsOptionsMode( true )}
|
||||
label={t( "All-observation-option" )}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{currentUser && renderLoggedIn( )}
|
||||
</View>
|
||||
</ScrollViewWrapper>
|
||||
|
||||
@@ -64,7 +64,7 @@ Add-optional-notes = Add optional notes
|
||||
Adds-your-vote-of-agreement = Adds your vote of agreement
|
||||
# Hint for a button that adds a vote of disagreement
|
||||
Adds-your-vote-of-disagreement = Adds your vote of disagreement
|
||||
Advanced--interface-mode = Advanced
|
||||
Advanced--interface-mode-with-explainer = Advanced (Upload multiple photos and sounds)
|
||||
Affiliation = Affiliation: { $site }
|
||||
# Label for button that adds an identification of the same taxon as another identification
|
||||
Agree = Agree
|
||||
@@ -581,7 +581,6 @@ iNaturalist-has-no-ID-suggestions-for-this-photo = iNaturalist has no ID suggest
|
||||
INATURALIST-HELP-PAGE = INATURALIST HELP PAGE
|
||||
iNaturalist-helps-you-identify = iNaturalist helps you identify the plants and animals around you while generating data for science and conservation. Get connected with a community of millions scientists and naturalists who can help you learn more about nature!
|
||||
iNaturalist-identification-suggestions-are-based-on = iNaturalist's identification suggestions are based on observations and identifications made by the iNaturalist community, including { $user1 }, { $user2 }, { $user3 }, and many others.
|
||||
INATURALIST-INTERFACE-MODE = INATURALIST INTERFACE MODE
|
||||
iNaturalist-is-a-501 = iNaturalist is a 501(c)(3) non-profit in the United States of America (Tax ID/EIN 92-1296468).
|
||||
iNaturalist-is-a-community-of-naturalists = iNaturalist is a community of naturalists that works together to create and identify wild biodiversity observations.
|
||||
iNaturalist-is-loading-ID-suggestions = iNaturalist is loading ID suggestions...
|
||||
@@ -589,6 +588,7 @@ iNaturalist-is-supported-by = iNaturalist is supported by an independent, 501(c)
|
||||
iNaturalist-is-supported-by-our-community = iNaturalist is supported by our amazing community. From everyday naturalists who add observations and identifications, to curators who manage our taxonomy and help with moderation, to the volunteer translators who make iNaturalist more accessible to worldwide audiences, to our community-based donors, we are extraordinarily grateful to all the people in our community who make iNaturalist the platform it is.
|
||||
iNaturalist-mission-is-to-connect = iNaturalist's mission is to connect people to nature and advance biodiversity science and conservation.
|
||||
INATURALIST-MISSION-VISION = INATURALIST'S MISSION & VISION
|
||||
INATURALIST-MODE = INATURALIST MODE
|
||||
INATURALIST-NETWORK = INATURALIST NETWORK
|
||||
INATURALIST-SETTINGS = INATURALIST SETTINGS
|
||||
# Label for the role a user plays on iNaturalist, e.g. "INATURALIST STAFF"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"Add-optional-notes": "Add optional notes",
|
||||
"Adds-your-vote-of-agreement": "Adds your vote of agreement",
|
||||
"Adds-your-vote-of-disagreement": "Adds your vote of disagreement",
|
||||
"Advanced--interface-mode": "Advanced",
|
||||
"Advanced--interface-mode-with-explainer": "Advanced (Upload multiple photos and sounds)",
|
||||
"Affiliation": "Affiliation: { $site }",
|
||||
"Agree": "Agree",
|
||||
"AGREE": "AGREE",
|
||||
@@ -337,7 +337,6 @@
|
||||
"INATURALIST-HELP-PAGE": "INATURALIST HELP PAGE",
|
||||
"iNaturalist-helps-you-identify": "iNaturalist helps you identify the plants and animals around you while generating data for science and conservation. Get connected with a community of millions scientists and naturalists who can help you learn more about nature!",
|
||||
"iNaturalist-identification-suggestions-are-based-on": "iNaturalist's identification suggestions are based on observations and identifications made by the iNaturalist community, including { $user1 }, { $user2 }, { $user3 }, and many others.",
|
||||
"INATURALIST-INTERFACE-MODE": "INATURALIST INTERFACE MODE",
|
||||
"iNaturalist-is-a-501": "iNaturalist is a 501(c)(3) non-profit in the United States of America (Tax ID/EIN 92-1296468).",
|
||||
"iNaturalist-is-a-community-of-naturalists": "iNaturalist is a community of naturalists that works together to create and identify wild biodiversity observations.",
|
||||
"iNaturalist-is-loading-ID-suggestions": "iNaturalist is loading ID suggestions...",
|
||||
@@ -345,6 +344,7 @@
|
||||
"iNaturalist-is-supported-by-our-community": "iNaturalist is supported by our amazing community. From everyday naturalists who add observations and identifications, to curators who manage our taxonomy and help with moderation, to the volunteer translators who make iNaturalist more accessible to worldwide audiences, to our community-based donors, we are extraordinarily grateful to all the people in our community who make iNaturalist the platform it is.",
|
||||
"iNaturalist-mission-is-to-connect": "iNaturalist's mission is to connect people to nature and advance biodiversity science and conservation.",
|
||||
"INATURALIST-MISSION-VISION": "INATURALIST'S MISSION & VISION",
|
||||
"INATURALIST-MODE": "INATURALIST MODE",
|
||||
"INATURALIST-NETWORK": "INATURALIST NETWORK",
|
||||
"INATURALIST-SETTINGS": "INATURALIST SETTINGS",
|
||||
"INATURALIST-STAFF": "{ $inaturalist } STAFF",
|
||||
|
||||
@@ -64,7 +64,7 @@ Add-optional-notes = Add optional notes
|
||||
Adds-your-vote-of-agreement = Adds your vote of agreement
|
||||
# Hint for a button that adds a vote of disagreement
|
||||
Adds-your-vote-of-disagreement = Adds your vote of disagreement
|
||||
Advanced--interface-mode = Advanced
|
||||
Advanced--interface-mode-with-explainer = Advanced (Upload multiple photos and sounds)
|
||||
Affiliation = Affiliation: { $site }
|
||||
# Label for button that adds an identification of the same taxon as another identification
|
||||
Agree = Agree
|
||||
@@ -581,7 +581,6 @@ iNaturalist-has-no-ID-suggestions-for-this-photo = iNaturalist has no ID suggest
|
||||
INATURALIST-HELP-PAGE = INATURALIST HELP PAGE
|
||||
iNaturalist-helps-you-identify = iNaturalist helps you identify the plants and animals around you while generating data for science and conservation. Get connected with a community of millions scientists and naturalists who can help you learn more about nature!
|
||||
iNaturalist-identification-suggestions-are-based-on = iNaturalist's identification suggestions are based on observations and identifications made by the iNaturalist community, including { $user1 }, { $user2 }, { $user3 }, and many others.
|
||||
INATURALIST-INTERFACE-MODE = INATURALIST INTERFACE MODE
|
||||
iNaturalist-is-a-501 = iNaturalist is a 501(c)(3) non-profit in the United States of America (Tax ID/EIN 92-1296468).
|
||||
iNaturalist-is-a-community-of-naturalists = iNaturalist is a community of naturalists that works together to create and identify wild biodiversity observations.
|
||||
iNaturalist-is-loading-ID-suggestions = iNaturalist is loading ID suggestions...
|
||||
@@ -589,6 +588,7 @@ iNaturalist-is-supported-by = iNaturalist is supported by an independent, 501(c)
|
||||
iNaturalist-is-supported-by-our-community = iNaturalist is supported by our amazing community. From everyday naturalists who add observations and identifications, to curators who manage our taxonomy and help with moderation, to the volunteer translators who make iNaturalist more accessible to worldwide audiences, to our community-based donors, we are extraordinarily grateful to all the people in our community who make iNaturalist the platform it is.
|
||||
iNaturalist-mission-is-to-connect = iNaturalist's mission is to connect people to nature and advance biodiversity science and conservation.
|
||||
INATURALIST-MISSION-VISION = INATURALIST'S MISSION & VISION
|
||||
INATURALIST-MODE = INATURALIST MODE
|
||||
INATURALIST-NETWORK = INATURALIST NETWORK
|
||||
INATURALIST-SETTINGS = INATURALIST SETTINGS
|
||||
# Label for the role a user plays on iNaturalist, e.g. "INATURALIST STAFF"
|
||||
|
||||
@@ -35,6 +35,12 @@ beforeAll( uniqueRealmBeforeAll );
|
||||
afterAll( uniqueRealmAfterAll );
|
||||
// /UNIQUE REALM SETUP
|
||||
|
||||
const toggleAdvancedMode = async ( ) => {
|
||||
const advancedRadioButton = await screen
|
||||
.findByText( /Advanced/ );
|
||||
fireEvent.press( advancedRadioButton );
|
||||
};
|
||||
|
||||
describe( "LanguageSettings", ( ) => {
|
||||
test( "uses locale preference of the local device", ( ) => {
|
||||
renderAppWithComponent( <Settings /> );
|
||||
@@ -63,12 +69,14 @@ describe( "LanguageSettings", ( ) => {
|
||||
|
||||
test( "uses locale preference from server", async ( ) => {
|
||||
renderAppWithComponent( <Settings /> );
|
||||
await toggleAdvancedMode( );
|
||||
const sciNameText = await screen.findByText( /Научное название/ );
|
||||
expect( sciNameText ).toBeVisible( );
|
||||
} );
|
||||
|
||||
test( "changes locales and updates server with new locale", async ( ) => {
|
||||
renderAppWithComponent( <Settings /> );
|
||||
await toggleAdvancedMode( );
|
||||
const changeLocaleButton = await screen.findByText( /CHANGE APP LANGUAGE/ );
|
||||
fireEvent.press( changeLocaleButton );
|
||||
const picker = await screen.findByTestId( "ReactNativePicker" );
|
||||
|
||||
@@ -26,6 +26,12 @@ jest.mock( "@react-navigation/native", ( ) => {
|
||||
|
||||
const initialStoreState = useStore.getState( );
|
||||
|
||||
const toggleAdvancedMode = async ( ) => {
|
||||
const advancedRadioButton = await screen
|
||||
.findByText( /Advanced/ );
|
||||
fireEvent.press( advancedRadioButton );
|
||||
};
|
||||
|
||||
beforeAll( async ( ) => {
|
||||
useStore.setState( initialStoreState, true );
|
||||
// userEvent recommends fake timers
|
||||
@@ -48,6 +54,7 @@ beforeEach( ( ) => {
|
||||
describe( "Settings", ( ) => {
|
||||
it( "should toggle the green observation button", async ( ) => {
|
||||
renderComponent( <Settings /> );
|
||||
await toggleAdvancedMode( );
|
||||
const aiCameraRow = await screen.findByLabelText( "iNaturalist AI Camera" );
|
||||
expect( aiCameraRow ).toHaveProp( "accessibilityState", expect.objectContaining( {
|
||||
checked: true
|
||||
@@ -73,6 +80,7 @@ describe( "Settings", ( ) => {
|
||||
|
||||
it( "should toggle taxon names display", async ( ) => {
|
||||
renderComponent( <Settings /> );
|
||||
await toggleAdvancedMode( );
|
||||
const sciNameFirst = await screen.findByLabelText( "Scientific Name (Common Name)" );
|
||||
expect( sciNameFirst ).toHaveProp( "accessibilityState", expect.objectContaining( {
|
||||
checked: false
|
||||
@@ -110,6 +118,7 @@ describe( "Settings", ( ) => {
|
||||
|
||||
it( "should not change state if taxon names toggled with no internet", async ( ) => {
|
||||
renderComponent( <Settings /> );
|
||||
await toggleAdvancedMode( );
|
||||
const sciNameFirst = await screen.findByLabelText( "Scientific Name (Common Name)" );
|
||||
expect( sciNameFirst ).toHaveProp( "accessibilityState", expect.objectContaining( {
|
||||
checked: false
|
||||
@@ -135,6 +144,7 @@ describe( "Settings", ( ) => {
|
||||
|
||||
test( "should change language immediately via language picker via online results", async ( ) => {
|
||||
renderComponent( <Settings /> );
|
||||
await toggleAdvancedMode( );
|
||||
const changeLanguageButton = await screen.findByText( /CHANGE APP LANGUAGE/ );
|
||||
fireEvent.press( changeLanguageButton );
|
||||
const picker = await screen.findByTestId( "ReactNativePicker" );
|
||||
|
||||
Reference in New Issue
Block a user