Fix Android crash on text string in Button component (#249)

* Remove TranslatedText component from Button and pass in translation strings via props
* Fix rendering of bottom sheets
This commit is contained in:
Amanda Bullington
2022-11-30 14:15:51 -08:00
committed by GitHub
parent e57ed1fdee
commit bb67cf0eeb
21 changed files with 84 additions and 154 deletions

View File

@@ -1,10 +1,10 @@
// @flow
import TranslatedText from "components/SharedComponents/TranslatedText";
import { Text, View } from "components/styledComponents";
import { t } from "i18next";
import { ExploreContext } from "providers/contexts";
import type { Node } from "react";
import React, { useContext } from "react";
import { View } from "react-native";
import { viewStyles } from "styles/explore/explore";
import DropdownPicker from "./DropdownPicker";
@@ -38,7 +38,7 @@ const Explore = ( ): Node => {
return (
<View style={viewStyles.bottomCard}>
<TranslatedText text="Explore" />
<Text>{t( "Explore" )}</Text>
<FiltersIcon />
<DropdownPicker
searchQuery={taxon}

View File

@@ -3,13 +3,12 @@
import CheckBox from "@react-native-community/checkbox";
import InputField from "components/SharedComponents/InputField";
import ScrollNoFooter from "components/SharedComponents/ScrollNoFooter";
import TranslatedText from "components/SharedComponents/TranslatedText";
import { Text, View } from "components/styledComponents";
import { t } from "i18next";
import { ExploreContext } from "providers/contexts";
import RadioButtonRN from "radio-buttons-react-native";
import type { Node } from "react";
import React, { useContext, useState } from "react";
import { View } from "react-native";
import RNPickerSelect from "react-native-picker-select";
import { pickerSelectStyles, viewStyles } from "styles/explore/exploreFilters";
@@ -283,7 +282,7 @@ const ExploreFilters = ( ): Node => {
<>
<ScrollNoFooter>
<TaxonLocationSearch />
<TranslatedText text="Sort-by" />
<Text>{t( "Sort-by" )}</Text>
<RadioButtonRN
data={sortByRadioButtons}
initial={1}
@@ -306,24 +305,24 @@ const ExploreFilters = ( ): Node => {
}}
/>
<View style={viewStyles.filtersRow}>
<TranslatedText text="Filters" />
<Text>{t( "Filters" )}</Text>
<ResetFiltersButton />
</View>
<TranslatedText text="Quality-Grade" />
<Text>{t( "Quality-Grade" )}</Text>
<View style={viewStyles.checkboxRow}>
{renderQualityGradeCheckbox( "research" )}
<TranslatedText text="Research-Grade" />
<Text>{t( "Research-Grade" )}</Text>
</View>
<View style={viewStyles.checkboxRow}>
{renderQualityGradeCheckbox( "needs_id" )}
<TranslatedText text="Needs-ID" />
<Text>{t( "Needs-ID" )}</Text>
</View>
<View style={viewStyles.checkboxRow}>
{renderQualityGradeCheckbox( "casual" )}
<TranslatedText text="Casual" />
<Text>{t( "Casual" )}</Text>
</View>
<TranslatedText text="User" />
<TranslatedText text="Search-for-a-user" />
<Text>{t( "User" )}</Text>
<Text>{t( "Search-for-a-user" )}</Text>
<DropdownPicker
searchQuery={user}
setSearchQuery={setUser}
@@ -331,8 +330,8 @@ const ExploreFilters = ( ): Node => {
sources="users"
value={userId}
/>
<TranslatedText text="Projects" />
<TranslatedText text="Search-for-a-project" />
<Text>{t( "Projects" )}</Text>
<Text>{t( "Search-for-a-project" )}</Text>
<DropdownPicker
searchQuery={project}
setSearchQuery={setProject}
@@ -340,41 +339,41 @@ const ExploreFilters = ( ): Node => {
sources="projects"
value={projectId}
/>
<TranslatedText text="Rank" />
<TranslatedText text="Low" />
<Text>{t( "Rank" )}</Text>
<Text>{t( "Low" )}</Text>
{renderRankPicker( "lrank" )}
<TranslatedText text="High" />
<Text>{t( "High" )}</Text>
{renderRankPicker( "hrank" )}
<TranslatedText text="Date" />
<TranslatedText text="Months" />
<Text>{t( "Date" )}</Text>
<Text>{t( "Months" )}</Text>
{renderMonthsPicker( )}
<TranslatedText text="Media" />
<Text>{t( "Media" )}</Text>
<View style={viewStyles.checkboxRow}>
{renderMediaCheckbox( "photos" )}
<TranslatedText text="Has-Photos" />
<Text>{t( "Has-Photos" )}</Text>
</View>
<View style={viewStyles.checkboxRow}>
{renderMediaCheckbox( "sounds" )}
<TranslatedText text="Has-Sounds" />
<Text>{t( "Has-Sounds" )}</Text>
</View>
<TranslatedText text="Status" />
<Text>{t( "Status" )}</Text>
<View style={viewStyles.checkboxRow}>
{renderStatusCheckbox( "introduced" )}
<TranslatedText text="Introduced" />
<Text>{t( "Introduced" )}</Text>
</View>
<View style={viewStyles.checkboxRow}>
{renderStatusCheckbox( "native" )}
<TranslatedText text="Native" />
<Text>{t( "Native" )}</Text>
</View>
<View style={viewStyles.checkboxRow}>
{renderStatusCheckbox( "threatened" )}
<TranslatedText text="Threatened" />
<Text>{t( "Threatened" )}</Text>
</View>
<View style={viewStyles.checkboxRow}>
{renderStatusCheckbox( "captive" )}
<TranslatedText text="Captive-Cultivated" />
<Text>{t( "Captive-Cultivated" )}</Text>
</View>
<TranslatedText text="Reviewed" />
<Text>{t( "Reviewed" )}</Text>
<RadioButtonRN
data={reviewedRadioButtons}
initial={1}
@@ -396,7 +395,7 @@ const ExploreFilters = ( ): Node => {
}
}}
/>
<TranslatedText text="Photo-Licensing" />
<Text>{t( "Photo-Licensing" )}</Text>
<RNPickerSelect
onValueChange={itemValue => {
setUnappliedFilters( {
@@ -413,7 +412,7 @@ const ExploreFilters = ( ): Node => {
: "all"
}
/>
<TranslatedText text="Description-Tags" />
<Text>{t( "Description-Tags" )}</Text>
<InputField
handleTextChange={q => {
setUnappliedFilters( {

View File

@@ -3,6 +3,7 @@
import { HeaderBackButton } from "@react-navigation/elements";
import { useNavigation } from "@react-navigation/native";
import Button from "components/SharedComponents/Buttons/Button";
import { t } from "i18next";
import { ExploreContext } from "providers/contexts";
import type { Node } from "react";
import React from "react";
@@ -29,7 +30,7 @@ const ExploreFooter = ( ): Node => {
<Button
level="primary"
onPress={applyFiltersAndNavigate}
text="Apply Filters"
text={t( "Apply Filters" )}
testID="ExploreFilters.applyFilters"
/>
</View>

View File

@@ -2,13 +2,12 @@
import { useNavigation } from "@react-navigation/native";
import Button from "components/SharedComponents/Buttons/Button";
import TranslatedText from "components/SharedComponents/TranslatedText";
import ViewWithFooter from "components/SharedComponents/ViewWithFooter";
// import DropdownPicker from "./DropdownPicker";
import { Text, View } from "components/styledComponents";
import { t } from "i18next";
import { ExploreContext } from "providers/contexts";
import type { Node } from "react";
import React, { useContext } from "react";
import { View } from "react-native";
import { textStyles, viewStyles } from "styles/explore/explore";
import FiltersIcon from "./FiltersIcon";
@@ -30,13 +29,15 @@ const Explore = ( ): Node => {
return (
<ViewWithFooter>
<TranslatedText style={textStyles.explanation} text="Visually-search-iNaturalist-data" />
<Text style={textStyles.explanation}>
{t( "Visually-search-iNaturalist-data" )}
</Text>
<FiltersIcon />
<TaxonLocationSearch />
<View style={viewStyles.positionBottom}>
<Button
level="primary"
text="Explore"
text={t( "Explore" )}
onPress={navToExplore}
// eslint-disable-next-line react-native/no-inline-styles
style={viewStyles.button}

View File

@@ -1,9 +1,9 @@
// @flow
import TranslatedText from "components/SharedComponents/TranslatedText";
import { Pressable, Text } from "components/styledComponents";
import { t } from "i18next";
import { ExploreContext } from "providers/contexts";
import * as React from "react";
import { Pressable } from "react-native";
import { viewStyles } from "styles/observations/messagesIcon";
const ResetFiltersButton = ( ): React.Node => {
@@ -14,7 +14,7 @@ const ResetFiltersButton = ( ): React.Node => {
onPress={resetFilters}
style={viewStyles.messages}
>
<TranslatedText text="Reset" />
<Text>{t( "Reset" )}</Text>
</Pressable>
);
};

View File

@@ -1,6 +1,7 @@
// @flow
import TranslatedText from "components/SharedComponents/TranslatedText";
import { Text } from "components/styledComponents";
import { t } from "i18next";
import { ExploreContext } from "providers/contexts";
import type { Node } from "react";
import React, { useCallback, useContext, useState } from "react";
@@ -54,7 +55,7 @@ const TaxonLocationSearch = ( ): Node => {
return (
<>
<TranslatedText text="Taxon" />
<Text>{t( "Taxon" )}</Text>
<DropdownPicker
zIndex={3000}
zIndexInverse={1000}
@@ -68,7 +69,7 @@ const TaxonLocationSearch = ( ): Node => {
onOpen={onTaxonOpen}
onClose={onClose}
/>
<TranslatedText text="Location" />
<Text>{t( "Location" )}</Text>
<DropdownPicker
zIndex={2000}
zIndexInverse={2000}

View File

@@ -2,6 +2,7 @@
import createIdentification from "api/identifications";
import Button from "components/SharedComponents/Buttons/Button";
import { t } from "i18next";
import type { Node } from "react";
import React, { useState } from "react";
import {
@@ -90,7 +91,7 @@ const GridItem = ( {
<Button
level="primary"
onPress={agreeWithObservation}
text="agree"
text={t( "agree" )}
testID="Identify.agree"
disabled={wasReviewed}
/>

View File

@@ -7,9 +7,9 @@ import {
SafeAreaView,
ScrollView
} from "components/styledComponents";
import { t } from "i18next";
import type { Node } from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import {
Linking,
Platform,
@@ -29,7 +29,6 @@ import {
import Logout from "./Logout";
const Login = ( ): Node => {
const { t } = useTranslation( );
const navigation = useNavigation( );
const [email, setEmail] = useState( "" );
const [password, setPassword] = useState( "" );
@@ -120,7 +119,7 @@ const Login = ( ): Node => {
{error && <Text className="text-red self-center mt-5">{error}</Text>}
<Button
level="primary"
text="Log-in"
text={t( "Log-in" )}
onPress={login}
style={viewStyles.button}
disabled={!email || !password}

View File

@@ -4,10 +4,10 @@ import { useNavigation } from "@react-navigation/native";
import { useQueryClient } from "@tanstack/react-query";
import Button from "components/SharedComponents/Buttons/Button";
import { View } from "components/styledComponents";
import { t } from "i18next";
import { RealmContext } from "providers/contexts";
import type { Node } from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import {
Dialog, Paragraph, Portal, Text
} from "react-native-paper";
@@ -22,7 +22,6 @@ const { useRealm } = RealmContext;
const Logout = ( ): Node => {
const navigation = useNavigation( );
const { t } = useTranslation( );
const [username, setUsername] = useState( null );
const [visible, setVisible] = useState( false );
const realm = useRealm( );
@@ -86,7 +85,7 @@ const Logout = ( ): Node => {
style={viewStyles.button}
onPress={showDialog}
testID="Login.signOutButton"
text="Sign-out"
text={t( "Sign-out" )}
/>
</View>
</>

View File

@@ -16,13 +16,13 @@ import {
Image, Pressable, Text, View
} from "components/styledComponents";
import { formatISO } from "date-fns";
import { t } from "i18next";
import _ from "lodash";
import { RealmContext } from "providers/contexts";
import type { Node } from "react";
import React, {
useEffect, useState
} from "react";
import { useTranslation } from "react-i18next";
import {
Alert, LogBox
} from "react-native";
@@ -55,7 +55,6 @@ LogBox.ignoreLogs( [
const ObsDetails = ( ): Node => {
const currentUser = useCurrentUser( );
const userId = currentUser?.id;
const { t } = useTranslation( );
const [refetch, setRefetch] = useState( false );
const [showCommentBox, setShowCommentBox] = useState( false );
const { params } = useRoute( );

View File

@@ -3,6 +3,7 @@
import { useNavigation } from "@react-navigation/native";
import PlaceholderText from "components/PlaceholderText";
import Button from "components/SharedComponents/Buttons/Button";
import { t } from "i18next";
import { ObsEditContext } from "providers/contexts";
import type { Node } from "react";
import React, { useContext } from "react";
@@ -34,15 +35,14 @@ const BottomModal = ( ): Node => {
<View style={viewStyles.saveButton}>
<Button
level="primary"
text="save"
text={t( "save" )}
testID="ObsEdit.saveButton"
onPress={saveObsAndNavigate}
/>
</View>
<Button
level="primary"
text="DELETE-X-OBSERVATIONS"
count={observations.length}
text={t( "DELETE-X-OBSERVATIONS", { count: observations.length } )}
onPress={deleteObsAndNavigate}
testID="ObsEdit.exitNavigation"
/>

View File

@@ -4,10 +4,10 @@ import { useNavigation } from "@react-navigation/native";
import Button from "components/SharedComponents/Buttons/Button";
import { Text, View } from "components/styledComponents";
import { iconicTaxaIds, iconicTaxaNames } from "dictionaries/iconicTaxaIds";
import { t } from "i18next";
import { ObsEditContext } from "providers/contexts";
import type { Node } from "react";
import React, { useContext } from "react";
import { useTranslation } from "react-i18next";
import { FlatList } from "react-native";
import { Avatar, useTheme } from "react-native-paper";
import { textStyles, viewStyles } from "styles/obsEdit/obsEdit";
@@ -18,7 +18,6 @@ const IdentificationSection = ( ): Node => {
updateTaxon
} = useContext( ObsEditContext );
const navigation = useNavigation( );
const { t } = useTranslation( );
const { colors } = useTheme( );
const identification = currentObservation.taxon;
@@ -65,7 +64,7 @@ const IdentificationSection = ( ): Node => {
<Button
level="primary"
onPress={navToAddID}
text="Add-an-Identification"
text={t( "Add-an-Identification" )}
style={viewStyles.button}
testID="ObsEdit.Suggestions"
/>

View File

@@ -4,6 +4,7 @@ import Button from "components/SharedComponents/Buttons/Button";
import InputField from "components/SharedComponents/InputField";
import Map from "components/SharedComponents/Map";
import ViewNoFooter from "components/SharedComponents/ViewNoFooter";
import { t } from "i18next";
import type { Node } from "react";
import React, { useEffect, useState } from "react";
import { View } from "react-native";
@@ -65,7 +66,7 @@ const LocationPicker = ( { closeLocationPicker, updateLocation }: Props ): Node
<View style={viewStyles.confirmButtonFooter}>
<Button
level="primary"
text="confirm location"
text={t( "confirm location" )}
onPress={updateLocationAndClose}
testID="LocationPicker.confirmButton"
/>

View File

@@ -6,13 +6,13 @@ import MediaViewerModal from "components/MediaViewer/MediaViewerModal";
import Button from "components/SharedComponents/Buttons/Button";
import KebabMenu from "components/SharedComponents/KebabMenu";
import { Text, View } from "components/styledComponents";
import { t } from "i18next";
import { ObsEditContext, RealmContext } from "providers/contexts";
import type { Node } from "react";
import React, {
useCallback, useContext, useEffect, useRef,
useState
} from "react";
import { useTranslation } from "react-i18next";
import { BackHandler } from "react-native";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { Menu } from "react-native-paper";
@@ -47,7 +47,6 @@ const ObsEdit = ( ): Node => {
) : [];
const navigation = useNavigation( );
const { params } = useRoute( );
const { t } = useTranslation( );
const localObservation = useLocalObservation( params?.uuid );
const isLoggedIn = useLoggedIn( );
const [mediaViewerVisible, setMediaViewerVisible] = useState( false );
@@ -106,7 +105,7 @@ const ObsEdit = ( ): Node => {
/>
</KebabMenu>
</>
), [deleteDialogVisible, t] );
), [deleteDialogVisible] );
useEffect( ( ) => {
const renderHeaderTitle = ( ) => <ObsEditHeaderTitle />;
@@ -181,7 +180,7 @@ const ObsEdit = ( ): Node => {
/>
<Button
level="primary"
text="UPLOAD-OBSERVATION"
text={t( "UPLOAD-OBSERVATION" )}
testID="ObsEdit.uploadButton"
onPress={saveAndUploadObservation}
disabled={!isLoggedIn}

View File

@@ -128,8 +128,6 @@ const ObservationViews = ( {
};
const renderBottomSheet = ( ) => {
if ( numOfUnuploadedObs === 0 ) { return null; }
if ( isLoggedIn === false ) {
return (
<BottomSheet hide={hasScrolled}>
@@ -145,15 +143,18 @@ const ObservationViews = ( {
/>
);
}
return (
<BottomSheet hide={hasScrolled}>
<UploadPrompt
uploadObservations={updateUploadStatus}
numOfUnuploadedObs={numOfUnuploadedObs}
updateUploadStatus={updateUploadStatus}
/>
</BottomSheet>
);
if ( numOfUnuploadedObs > 0 && isLoggedIn ) {
return (
<BottomSheet hide={hasScrolled}>
<UploadPrompt
uploadObservations={updateUploadStatus}
numOfUnuploadedObs={numOfUnuploadedObs}
updateUploadStatus={updateUploadStatus}
/>
</BottomSheet>
);
}
return null;
};
const renderFooter = ( ) => {
@@ -200,7 +201,7 @@ const ObservationViews = ( {
bounces={false}
contentContainerStyle={{ minHeight: flatListHeight }}
/>
{renderBottomSheet( )}
{numOfUnuploadedObs > 0 && renderBottomSheet( )}
</>
);
};

View File

@@ -74,7 +74,7 @@ const GroupPhotosFooter = ( {
<View className="w-28">
<Button
level="secondary"
text="Next"
text={t( "Next" )}
onPress={navToObsEdit}
testID="GroupPhotos.next"
/>

View File

@@ -226,8 +226,7 @@ const PhotoGallery = ( ): Node => {
<View className="h-16 mt-2 mx-4">
<Button
level="secondary"
text="Import-X-photos"
count={totalSelected || 0}
text={t( "Import-X-photos", { count: totalSelected || 0 } )}
onPress={navToNextScreen}
testID="PhotoGallery.createObsButton"
/>

View File

@@ -1,6 +1,6 @@
// @flow
import TranslatedText from "components/SharedComponents/TranslatedText";
import { Text } from "components/styledComponents";
import * as React from "react";
import { Button as ButtonRNP } from "react-native-paper";
@@ -9,7 +9,6 @@ type ButtonProps = {
disabled?: boolean,
onPress: any,
level?: string,
count?: number,
testID?: string,
loading?: boolean,
style?: any,
@@ -49,7 +48,7 @@ const setStyles = ( {
};
const Button = ( {
text, onPress, disabled, testID, count, level, loading, style, className
text, onPress, disabled, testID, level, loading, style, className
}: ButtonProps ): React.Node => {
const { buttonClass } = setStyles( { disabled, level, className } );
@@ -62,11 +61,9 @@ const Button = ( {
testID={testID}
loading={loading}
>
<TranslatedText
count={count}
className="text-lg text-white font-semibold"
text={text}
/>
<Text className="text-lg text-white font-semibold">
{text}
</Text>
</ButtonRNP>
);
};

View File

@@ -1,42 +0,0 @@
// @flow
import TranslatedText from "components/SharedComponents/TranslatedText";
import * as React from "react";
import { Button } from "react-native-paper";
import { textStyles, viewStyles } from "styles/sharedComponents/buttons/roundGrayButton";
type Props = {
buttonText: string,
count?: number,
disabled?: boolean,
handlePress: any,
loading?: boolean,
style?: any,
testID: string
}
const RoundGrayButton = ( {
buttonText,
count,
disabled,
handlePress,
loading,
style,
testID
}: Props ): React.Node => (
<Button
disabled={disabled}
loading={loading}
onPress={handlePress}
style={[style, viewStyles.grayButton, disabled && viewStyles.disabled]}
testID={testID}
uppercase={false}
>
<TranslatedText
count={count}
style={[textStyles.grayButtonText, disabled && textStyles.disabled]}
text={buttonText}
/>
</Button>
);
export default RoundGrayButton;

View File

@@ -1,24 +0,0 @@
// @flow
import type { Node } from "react";
import React from "react";
import { useTranslation } from "react-i18next";
import { Text } from "react-native";
type Props = {
text: string,
style?: any,
className?: string,
count?: number
}
const TranslatedText = ( {
text, style, className, count
}: Props ): Node => {
const { t } = useTranslation( );
// $FlowIgnore
return <Text className={className} style={style}>{t( text, { count } )}</Text>;
};
export default TranslatedText;

View File

@@ -102,7 +102,7 @@ const UserProfile = ( ): React.Node => {
<View className="w-1/2">
<Button
level="primary"
text="Follow"
text={t( "Follow" )}
onPress={followUser}
testID="UserProfile.followButton"
/>
@@ -110,7 +110,7 @@ const UserProfile = ( ): React.Node => {
<View className="w-1/2">
<Button
level="primary"
text="Messages"
text={t( "Messages" )}
onPress={( ) => console.log( "open messages" )}
testID="UserProfile.messagesButton"
/>