react-native-safe-area-context#useSafeAreaInsets JavaScript Examples
The following examples show how to use
react-native-safe-area-context#useSafeAreaInsets.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js From stayaway-app with European Union Public License 1.2 | 6 votes |
export default function Layout(props) {
const { padding, style, children, ...otherProps } = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
return (
<View
style={{
...memoizedStyle.container,
...memoizedStyle[padding],
...style,
}}
{...otherProps}
>
{children}
</View>
);
}
Example #2
Source File: index.js From stayaway-app with European Union Public License 1.2 | 6 votes |
export default function TabBar(props) {
const infected = useSelector(isInfected);
const insets = useSafeAreaInsets();
const { colors } = useTheme();
if (infected) {
return null;
}
return (
<BottomTabBar
{...props}
showLabel={false}
style={{
...styles.container,
height: 56 + insets.bottom,
backgroundColor: colors.tabBarBackgroundColor,
}}
/>
);
}
Example #3
Source File: Unsupported.js From stayaway-app with European Union Public License 1.2 | 6 votes |
export default function Unsupported (props) {
const { supportedVersion } = props;
const insets = useSafeAreaInsets();
const { name } = useTheme();
const memoizedStyle = useMemo(() => styles(insets), [insets]);
return (
<TopComponent>
<Layout>
<Text size='large' weight='bold' textAlign='center' style={memoizedStyle.title}>{i18n.translate('screens.unsupported.title')}</Text>
<Text>{i18n.translate('screens.unsupported.description', { supported_version: supportedVersion })}</Text>
</Layout>
<View style={memoizedStyle.imagesContainer}>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #4
Source File: Template.js From stayaway-app with European Union Public License 1.2 | 6 votes |
export default function Template (props) {
const { header, description, image, pressable, closable, onPress, onClose } = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
return (
<TopComponent>
<ImageBackground
source={image}
style={memoizedStyle.imageContainer}
>
<View style={memoizedStyle.topContainer}>
{ closable &&
<Layout style={memoizedStyle.top}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.how_to_use.actions.back.accessibility.hint.label')}
accessibilityHint={i18n.translate('screens.how_to_use.actions.back.accessibility.hint.hint')}
>
<Icon name='arrow' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
</Layout>
}
</View>
<View style={memoizedStyle.bottomContainer}>
{renderContent(header, description, pressable, onPress, memoizedStyle)}
</View>
</ImageBackground>
</TopComponent>
);
}
Example #5
Source File: TermsOfUse.js From stayaway-app with European Union Public License 1.2 | 5 votes |
export default function TermsOfUse(props) {
const {
onClose,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
return (
<TopComponent scrollable={false} style={memoizedStyle.container}>
<Layout style={memoizedStyle.layoutContainer} padding='top'>
<View style={memoizedStyle.header}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.terms_of_use.actions.back.accessibility.label')}
accessibilityHint={i18n.translate('screens.terms_of_use.actions.back.accessibility.hint')}
>
<Icon name='arrow' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
<Text size='xlarge' weight='bold' style={memoizedStyle.headerTitle}>{i18n.translate('screens.terms_of_use.title')}</Text>
</View>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={memoizedStyle.bodyContainer}
>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.scope_and_purpose.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.scope_and_purpose.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.conditions_of_access_and_use.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.conditions_of_access_and_use.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.features_of_the_app.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.features_of_the_app.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.users_duties_of_care.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.users_duties_of_care.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.liability_and_warranty.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.liability_and_warranty.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.data_protection.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.data_protection.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.termination_of_use.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.termination_of_use.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.copyright_property_rights_and_rights_of_use.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.copyright_property_rights_and_rights_of_use.description')}</Text>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.terms_of_use.final_provisions.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.terms_of_use.final_provisions.description')}</Text>
</View>
<Text textColor={colors.settingsLabelTextColor} size='xsmall' weight='bold'>{i18n.translate('screens.terms_of_use.last_review')}</Text>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
</ScrollView>
</Layout>
<View style={memoizedStyle.imagesContainer}>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #6
Source File: Licenses.js From stayaway-app with European Union Public License 1.2 | 5 votes |
export default function Licenses(props) {
const {
licenses,
onClose,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
return (
<TopComponent scrollable={false} style={memoizedStyle.container}>
<Layout style={memoizedStyle.layoutContainer} padding='top'>
<View style={memoizedStyle.header}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.licenses.actions.back.accessibility.label')}
accessibilityHint={i18n.translate('screens.licenses.actions.back.accessibility.hint')}
>
<Icon name='arrow' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
<Text size='xlarge' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.licenses.title')}</Text>
</View>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={memoizedStyle.bodyContainer}
>
<View style={memoizedStyle.projectInformation}>
<Text textColor={colors.licensesProjectTextColor}>{i18n.translate('screens.licenses.project')}</Text>
</View>
<View style={memoizedStyle.copyrightAndLicense}>
<Text textColor={colors.licensesTitleTextColor} weight='bold' style={memoizedStyle.copyrightAndLicenseTitle}>{i18n.translate('screens.licenses.copyright_and_license.title')}</Text>
<Text>{i18n.translate('screens.licenses.copyright_and_license.body')}</Text>
</View>
<View style={memoizedStyle.thirdPartyLicenses}>
<Text textColor={colors.licensesTitleTextColor} weight='bold' style={memoizedStyle.thirdPartyLicensesTitle}>{i18n.translate('screens.licenses.third_party.title')}</Text>
{renderThirdPartyLicenses(licenses, colors, memoizedStyle)}
</View>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
</ScrollView>
</Layout>
<View style={memoizedStyle.imagesContainer}>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #7
Source File: LegalInformation.js From stayaway-app with European Union Public License 1.2 | 5 votes |
export default function LegalInformation(props) {
const {
onClose,
onPressPrivacyPolicy,
onPressTermsOfUse,
onPressTechnicalSheet,
onPressLicenses,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
const topItems = [
{
id: 1,
title: i18n.translate('screens.legal_information.terms_of_use.label'),
onPress: onPressTermsOfUse,
accessibilityLabel: i18n.translate('screens.legal_information.terms_of_use.accessibility.label'),
accessibilityHint: i18n.translate('screens.legal_information.terms_of_use.accessibility.hint'),
},
{
id: 2,
title: i18n.translate('screens.legal_information.privacy_policy.label'),
onPress: onPressPrivacyPolicy,
accessibilityLabel: i18n.translate('screens.legal_information.privacy_policy.accessibility.label'),
accessibilityHint: i18n.translate('screens.legal_information.privacy_policy.accessibility.hint'),
},
];
const bottomItems = [
{
id: 1,
title: i18n.translate('screens.legal_information.technical_sheet.label'),
onPress: onPressTechnicalSheet,
accessibilityLabel: i18n.translate('screens.legal_information.technical_sheet.accessibility.label'),
accessibilityHint: i18n.translate('screens.legal_information.technical_sheet.accessibility.hint'),
},
{
id: 2,
title: i18n.translate('screens.legal_information.licenses.label'),
onPress: onPressLicenses,
accessibilityLabel: i18n.translate('screens.legal_information.licenses.accessibility.label'),
accessibilityHint: i18n.translate('screens.legal_information.licenses.accessibility.hint'),
},
];
return (
<TopComponent style={memoizedStyle.container}>
<Layout style={memoizedStyle.layoutContainer}>
<View style={memoizedStyle.header}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.legal_information.actions.back.accessibility.label')}
accessibilityHint={i18n.translate('screens.legal_information.actions.back.accessibility.hint')}
>
<Icon name='arrow' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
<Text size='xlarge' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.legal_information.title')}</Text>
</View>
<List style={memoizedStyle.itemsContainer} items={topItems} />
<List style={memoizedStyle.itemsContainer} items={bottomItems} />
</Layout>
<View style={memoizedStyle.imagesContainer}>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #8
Source File: HowToUse.js From stayaway-app with European Union Public License 1.2 | 5 votes |
export default function HowToUse (props) {
const {
shouldShowLocationScreen,
onPress,
onClose,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(insets), [insets]);
return (
<Swiper
loop={false}
showsButtons
buttonWrapperStyle={memoizedStyle.buttonWrapperStyle}
paginationStyle={memoizedStyle.paginationStyle}
nextButton={<Icon name='chevron_right' width={iconSizes.size14} height={iconSizes.size22} />}
prevButton={<Icon name='chevron_left' width={iconSizes.size14} height={iconSizes.size22} />}
style={memoizedStyle.container}
dotColor={colors.iconMainTintColor}
dotStyle={memoizedStyle.dotStyle}
activeDotColor={colors.iconMainTintColor}
activeDotStyle={memoizedStyle.activeDotStyle}
>
<Template
header={i18n.translate('screens.onboarding.first.title')}
image={getThemedImage('onboarding1', name)}
closable
onClose={onClose}
/>
<Template
header={i18n.translate('screens.onboarding.second.title')}
description={i18n.translate('screens.onboarding.second.description')}
image={getThemedImage('onboarding2', name)}
/>
<Template
header={i18n.translate('screens.onboarding.third.title')}
description={i18n.translate('screens.onboarding.third.description')}
image={getThemedImage('onboarding3', name)}
/>
<Template
header={i18n.translate('screens.onboarding.fourth.title')}
description={i18n.translate('screens.onboarding.fourth.description')}
image={getThemedImage('onboarding4', name)}
pressable={!shouldShowLocationScreen}
onPress={onPress}
/>
{shouldShowLocationScreen &&
<Template
header={i18n.translate('screens.onboarding.fifth.title')}
description={i18n.translate('screens.onboarding.fifth.description')}
image={getThemedImage('onboarding5', name)}
pressable
onPress={onPress}
/>
}
</Swiper>
);
}
Example #9
Source File: Debug.js From stayaway-app with European Union Public License 1.2 | 5 votes |
export default function Debug (props) {
const {
signUp,
status,
onClose,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
let infectionStatusName = i18n.translate('screens.debug.infection_status.healthy');
if (status.infectionStatus === INFECTION_STATUS.EXPOSED ) {
infectionStatusName = i18n.translate('screens.debug.infection_status.exposed');
}
if (status.infectionStatus === INFECTION_STATUS.INFECTED ) {
infectionStatusName = i18n.translate('screens.debug.infection_status.infected');
}
const exposedDays =
status?.exposureDays
.map(day => Moment(day.exposedDate).format('L'))
.join(',');
const errors = status?.errors.join(',');
return (
<TopComponent>
<Layout style={memoizedStyle.layoutContainer}>
<View style={memoizedStyle.header}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.debug.actions.back.accessibility.label')}
accessibilityHint={i18n.translate('screens.debug.actions.back.accessibility.hint')}
>
<Icon name='arrow' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
<Text size='xlarge' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.debug.title')}</Text>
</View>
<View style={memoizedStyle.content}>
<View style={memoizedStyle.stat}>
<Text weight='bold'>{`${i18n.translate('screens.debug.sign_up')}: `}</Text>
<Text>{Moment(signUp).format('L')}</Text>
</View>
<View style={memoizedStyle.stat}>
<Text weight='bold'>{`${i18n.translate('screens.debug.last_sync')}: `}</Text>
<Text>{Moment(status.lastSyncDate).format('L')}</Text>
</View>
<View style={memoizedStyle.stat}>
<Text weight='bold'>{`${i18n.translate('screens.debug.infection_status.label')}: `}</Text>
<Text>{infectionStatusName}</Text>
</View>
<View style={memoizedStyle.stat}>
<Text weight='bold'>{`${i18n.translate('screens.debug.exposure_days')}: `}</Text>
<Text>{exposedDays}</Text>
</View>
<View style={memoizedStyle.stat}>
<Text weight='bold'>{`${i18n.translate('screens.debug.errors')}: `}</Text>
<Text>{errors}</Text>
</View>
</View>
</Layout>
<View style={memoizedStyle.imagesContainer}>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #10
Source File: index.js From stayaway-app with European Union Public License 1.2 | 5 votes |
export default function Onboarding (props) {
const {
loading,
shouldShowLocationScreen,
onPress,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(insets), [insets]);
return (
<Swiper
testID="onboarding"
loop={false}
showsButtons
buttonWrapperStyle={memoizedStyle.buttonWrapperStyle}
paginationStyle={memoizedStyle.paginationStyle}
nextButton={<Icon name='chevron_right' width={iconSizes.size14} height={iconSizes.size22} />}
prevButton={<Icon name='chevron_left' width={iconSizes.size14} height={iconSizes.size22} />}
style={memoizedStyle.container}
dotColor={colors.iconMainTintColor}
dotStyle={memoizedStyle.dotStyle}
activeDotColor={colors.iconMainTintColor}
activeDotStyle={memoizedStyle.activeDotStyle}
>
<Template
header={i18n.translate('screens.onboarding.first.title')}
image={getThemedImage('onboarding1', name)}
/>
<Template
header={i18n.translate('screens.onboarding.second.title')}
description={i18n.translate('screens.onboarding.second.description')}
image={getThemedImage('onboarding2', name)}
/>
<Template
header={i18n.translate('screens.onboarding.third.title')}
description={i18n.translate('screens.onboarding.third.description')}
image={getThemedImage('onboarding3', name)}
/>
<Template
header={i18n.translate('screens.onboarding.fourth.title')}
description={i18n.translate('screens.onboarding.fourth.description')}
image={getThemedImage('onboarding4', name)}
/>
{shouldShowLocationScreen &&
<Template
header={i18n.translate('screens.onboarding.fifth.title')}
description={i18n.translate('screens.onboarding.fifth.description')}
image={getThemedImage('onboarding5', name)}
/>
}
<Consent loading={loading} onPress={onPress} />
</Swiper>
);
}
Example #11
Source File: Transaction.js From actual with MIT License | 5 votes |
function Transaction(props) {
const insets = useSafeAreaInsets();
return <_Transaction insets={insets} {...props} />;
}
Example #12
Source File: Template.js From stayaway-app with European Union Public License 1.2 | 4 votes |
export default function Template (props) {
const {
header,
description,
image,
panelBackgroundColor,
panelTextColor,
lastSync,
onPressSettings,
onLongPressSettings,
onPressShare,
error,
infectionStatus,
} = props;
const showUpdatedAt = infectionStatus !== INFECTION_STATUS.INFECTED;
const hasUpdated = lastSync !== 0;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
return (
<TopComponent>
<View style={memoizedStyle.settingsButtonContainer} pointerEvents='box-none'>
<ButtonWrapper
onPress={onPressSettings}
onLongPress={onLongPressSettings}
style={memoizedStyle.settingsButton}
accessibilityLabel={i18n.translate('screens.home.actions.settings.accessibility.label')}
accessibilityHint={i18n.translate('screens.home.actions.settings.accessibility.hint')}
>
<Icon name='settings' width={iconSizes.size32} height={iconSizes.size32} />
</ButtonWrapper>
<ButtonWrapper
onPress={onPressShare}
style={memoizedStyle.shareButton}
accessibilityLabel={i18n.translate('screens.home.actions.share.accessibility.label')}
accessibilityHint={i18n.translate('screens.home.actions.share.accessibility.hint')}
>
<Icon
name='share'
width={iconSizes.size20}
height={iconSizes.size20}
/>
</ButtonWrapper>
</View>
{ error.status && renderError(error, colors, memoizedStyle) }
<View style={memoizedStyle.homeContainer}>
<ImageBackground
testID="home_image_background"
source={image}
style={memoizedStyle.imageContainer}
/>
<Layout
padding='horizontal'
style={memoizedStyle.contentContainer}
>
<View style={memoizedStyle.header}>
<View>
<View
style={{
...memoizedStyle.backgroundPanel,
backgroundColor: panelBackgroundColor,
}}
/>
<View style={memoizedStyle.panel}>
<View style={memoizedStyle.panelContainer}>
<Text size='xlarge' weight='bold' textColor={panelTextColor}>{header}</Text>
</View>
</View>
</View>
<View style={memoizedStyle.supportContainer}>
{ showUpdatedAt && hasUpdated &&
<SupportIcon
label={i18n.translate('screens.home.last_updated')}
content={lastSync.format('L')}
borderColor={panelBackgroundColor}
/>
}
{ showUpdatedAt && !hasUpdated &&
<SupportIcon
content={i18n.translate('screens.home.never_updated')}
borderColor={panelBackgroundColor}
/>
}
{ ! showUpdatedAt &&
<SupportIcon />
}
</View>
</View>
<Text style={memoizedStyle.descriptionsContent}>
{description}
</Text>
</Layout>
</View>
</TopComponent>
);
}
Example #13
Source File: Home.jsx From react-native-big-list with Apache License 2.0 | 4 votes |
Home = () => {
const {
colors: { background, surface },
} = useTheme();
const [openSelector, setOpenSelector] = useState(false);
const [selected, setSelected] = useState("standard");
const [insetBottom, setInsetBottom] = useState(0);
const insets = useSafeAreaInsets();
const options = [
{ label: "Standard List", value: "standard" },
{ label: "Columns List", value: "columns" },
{ label: "Sections List", value: "sections" },
{ label: "Multiselect List", value: "multiselect" },
{ label: "Compare List", value: "compare" },
];
const selectedOption = options.find((item) => item.value === selected);
return (
<View
style={[
styles.container,
{
backgroundColor: background,
paddingBottom: insetBottom + insets.bottom + 64,
},
]}
>
<Appbar.Header style={[styles.header, { height: 75 }]}>
<Appbar.Content title="BigList Example" subtitle="10.000 items" />
</Appbar.Header>
<TouchableOpacity
style={[
styles.containerBottom,
{ backgroundColor: surface, bottom: insets.bottom },
]}
onPress={() => setOpenSelector(!openSelector)}
onLayout={(event) => {
setInsetBottom(event.height || 0);
}}
>
<TextInput
label="View mode"
editable={false}
onTouchStart={() => setOpenSelector(true)}
value={selectedOption.label}
right={
<TextInput.Icon
name="chevron-down"
onPress={() => setOpenSelector(!openSelector)}
/>
}
/>
</TouchableOpacity>
{selected === "standard" ? (
<List />
) : selected === "columns" ? (
<ColumnsList />
) : selected === "sections" ? (
<SectionList />
) : selected === "multiselect" ? (
<MultiSelectList />
) : selected === "compare" ? (
<CompareList />
) : null}
{openSelector && (
<View
style={[
StyleSheet.absoluteFill,
{ flex: 1, backgroundColor: surface },
]}
>
<Appbar.Header style={[styles.header, { height: 75 }]}>
<Appbar.Content
title="View mode"
subtitle="Select the list view mode example..."
/>
</Appbar.Header>
<SelectList
data={options}
value={selected}
onSelect={(value) => {
setSelected(value);
setOpenSelector(false);
}}
/>
</View>
)}
</View>
);
}
Example #14
Source File: HomeScreen.js From hero with MIT License | 4 votes |
HomeScreen = ({ navigation }) => {
const [XMen, popularHeroes, villains] = useContext(HeroesContext);
const [loading, setLoading] = useState(false);
const insets = useSafeAreaInsets();
const scrollY = new Animated.Value(0);
const translateY = scrollY.interpolate({
inputRange: [40, 100 + insets.top],
outputRange: [40, insets.top - 100],
extrapolate: "clamp",
});
const search = async (item) => {
try {
setLoading(true);
const searchResponse = await fetch(
`https://superheroapi.com/api/${api.key}/${item.id}/`
);
const characterResponse = await fetch(
`https://comicvine.gamespot.com/api/characters/?api_key=${apiComicVine.key}&filter=name:${item.title},publisher${item.publisher}&field_list=deck,publisher,first_appeared_in_issue&format=json`
);
const hero = await searchResponse.json();
const characterInfo = await characterResponse.json();
summary = characterInfo.results[0].deck;
firstIssue = characterInfo.results[0].first_appeared_in_issue;
publisher = characterInfo.results[0].publisher.name;
const firstComicResponse = await fetch(
`https://comicvine.gamespot.com/api/issue/4000-${firstIssue.id}/?api_key=${apiComicVine.key}&format=json`
);
const firstComicInfo = await firstComicResponse.json();
firstIssueURL = firstComicInfo.results.image.original_url;
navigation.navigate("Character", {
hero: hero,
image: item.image,
// publisher: item.publisher,
comicPicture: comicPicture,
summary: summary,
firstIssue: firstIssue,
firstIssueURL: firstIssueURL,
publisher: publisher,
});
// setLoading(false);
} catch (error) {
console.error(error);
setLoading(false);
}
};
const _renderItem = ({ item, index }) => {
return (
<Pressable
key={index}
style={({ pressed }) => [
styles.heroCard,
{ opacity: pressed ? 0.8 : 1.0 },
]}
style={styles.heroCard}
>
<TouchableScale
delayPressIn={50}
activeScale={0.9}
tension={160}
friction={2}
onPress={() => {
search(item);
// console.log(item.id);
}}
>
<MaskedView
maskElement={
<SquircleView
style={StyleSheet.absoluteFill}
squircleParams={{
cornerRadius: 50,
cornerSmoothing: 1,
fillColor: "pink",
}}
/>
}
>
<Image
source={item.image}
resizeMode="cover"
PlaceholderContent={<ActivityIndicator />}
style={{
width: "100%",
height: "100%",
}}
/>
<View
style={{
flex: 1,
position: "absolute",
bottom: -5,
padding: 30,
width: "100%",
justifyContent: "center",
borderRadius: 20,
}}
>
<Text
style={{
...styles.h4,
fontSize: 20,
color: COLORS.beige,
textShadowColor: "rgba(0, 0, 0, 1)",
textShadowOffset: { width: -1, height: 1 },
textShadowRadius: 5,
}}
>
{item.title}
</Text>
</View>
</MaskedView>
</TouchableScale>
</Pressable>
// </Animated.View>
);
};
useEffect(() => {
setLoading(false);
}, []);
useEffect(() => {
const unsubscribe = navigation.addListener("blur", () => {
// Screen was blurred
// Do something
setLoading(false);
});
return unsubscribe;
}, [navigation]);
return (
<>
<View style={styles.appContainer}>
<StatusBar
translucent
backgroundColor="transparent"
barStyle="dark-content"
/>
<SafeAreaView
style={{
flex: 1,
width: Dimensions.get("window").width,
}}
forceInset={{ top: "always" }}
>
<Animated.View
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
zIndex: 10,
height: 100,
transform: [{ translateY: translateY }],
}}
>
<View style={styles.header}>
<View style={{ justifyContent: "flex-end" }}>
<Text style={styles.appTitle}>hero</Text>
<Text
style={{ ...styles.p, fontSize: 7, marginTop: -2, left: -2 }}
>
the Superhero Encyclopedia
</Text>
</View>
</View>
</Animated.View>
<ScrollView
contentContainerStyle={{
paddingBottom: 80,
width: Dimensions.get("window").width,
}}
onScroll={(e) => {
scrollY.setValue(e.nativeEvent.contentOffset.y);
}}
scrollEventThrottle={6}
>
<View style={styles.popularContainer}>
<View
style={{
flexDirection: "row",
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
}}
>
<Text
style={{
...styles.h4,
marginBottom: 10,
paddingLeft: 15,
}}
>
Popular
</Text>
<Icon
name="trending-up"
type="feather"
color={COLORS.navy}
size={30}
iconStyle={{ bottom: 2, paddingLeft: 5 }}
/>
</View>
<Carousel
data={popularHeroes}
sliderWidth={380}
itemWidth={260}
renderItem={_renderItem}
loop={true}
inactiveSlideShift={0}
inactiveSlideOpacity={Platform.OS === "ios" ? 0.5 : 1}
/>
</View>
<View style={styles.heroContainer}>
<View
style={{
flexDirection: "row",
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
}}
>
<Text
style={{
...styles.h4,
marginBottom: 10,
paddingLeft: 15,
}}
>
Villians
</Text>
<Icon
name="emoticon-devil"
type="material-community"
color={COLORS.navy}
size={30}
iconStyle={{ bottom: 2, paddingLeft: 5, opacity: 0.9 }}
/>
</View>
<Carousel
data={villains}
sliderWidth={380}
itemWidth={260}
renderItem={_renderItem}
loop={true}
// inactiveSlideShift={-24}
inactiveSlideOpacity={Platform.OS === "ios" ? 0.5 : 1}
/>
</View>
<View style={styles.heroContainer}>
<Text
style={{
...styles.h4,
marginBottom: 10,
paddingHorizontal: 15,
}}
>
X-Men
</Text>
<Carousel
data={XMen}
sliderWidth={380}
itemWidth={260}
renderItem={_renderItem}
loop={true}
// inactiveSlideShift={-24}
inactiveSlideOpacity={Platform.OS === "ios" ? 0.5 : 1}
/>
</View>
</ScrollView>
{/* )} */}
<LinearGradient
colors={[COLORS.beige, "#ffffff00"]}
style={styles.scrollGradient}
locations={[0, 1]}
pointerEvents={"none"}
/>
</SafeAreaView>
</View>
{loading === true ? (
<Modal statusBarTranslucent={true}>
<View
style={{
backgroundColor: COLORS.beige,
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Progress.CircleSnail
color={[COLORS.navy, COLORS.orange, COLORS.blue]}
size={80}
thickness={10}
style={styles.loading}
strokeCap={"round"}
/>
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
marginTop: -15,
left: 3,
}}
>
loading...
</Text>
</View>
</Modal>
) : null}
</>
);
}
Example #15
Source File: Info.js From stayaway-app with European Union Public License 1.2 | 4 votes |
export default function Info(props) {
const {
appVersion,
appBuild,
language,
theme,
tracingEnabled,
isInfected,
onClose,
onPressLanguage,
onPressTheme,
onPressSupport,
onPressLegalInformation,
onPressHowToUse,
onPressFaqs,
onPressTracing,
onPressDebug,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
const languagesNames = Object.values(languages).map(({ languageTag, countryCode }) => ({ id: languageTag, label: countryCode }));
const themesNames = Object.values(commonThemes.names).map(id => ({ id, label: i18n.translate(`screens.settings.theme.${id}`) }));
const topItems = [
{
id: 1,
onPress: onPressTracing,
style: {
...memoizedStyle.tracingItem,
backgroundColor: tracingEnabled ? colors.settingsMainButtonBackgroundColor : colors.settingsAltButtonBackgroundColor,
},
disabled: isInfected,
accessibilityRole: 'switch',
accessibilityValue: { text: tracingEnabled },
accessibilityLabel: i18n.translate('screens.settings.tracing.accessibility.label'),
accessibilityHint: i18n.translate(`screens.settings.tracing.accessibility.hint.${tracingEnabled ? 'deactivate' : 'activate'}`),
renderItem: () => renderTracingButton(tracingEnabled, onPressTracing, colors, memoizedStyle),
},
{
id: 2,
title: i18n.translate('screens.settings.language.label'),
onPress: onPressLanguage,
accessibilityLabel: i18n.translate('screens.settings.language.accessibility.label'),
accessibilityHint: i18n.translate('screens.settings.language.accessibility.hint'),
accessibilityRole: 'switch',
accessibilityValue: { text: language.name },
icon: <Toggle value={language.languageTag} options={languagesNames} onPress={onPressLanguage} />,
},
{
id: 3,
title: i18n.translate('screens.settings.theme.label'),
onPress: onPressTheme,
accessibilityLabel: i18n.translate('screens.settings.theme.accessibility.label'),
accessibilityHint: i18n.translate('screens.settings.theme.accessibility.hint'),
accessibilityRole: 'switch',
accessibilityValue: { text: i18n.translate(`screens.settings.theme.${theme}`) },
icon: <Toggle value={theme} options={themesNames} onPress={onPressTheme} />,
},
];
const bottomItems = [
{
id: 1,
title: i18n.translate('screens.settings.how_to_use.label'),
onPress: onPressHowToUse,
accessibilityLabel: i18n.translate('screens.settings.how_to_use.accessibility.label'),
accessibilityHint: i18n.translate('screens.settings.how_to_use.accessibility.hint'),
},
{
id: 2,
title: i18n.translate('screens.settings.faqs.label'),
onPress: onPressFaqs,
accessibilityLabel: i18n.translate('screens.settings.faqs.accessibility.label'),
accessibilityHint: i18n.translate('screens.settings.faqs.accessibility.hint'),
icon: <Icon name='external_link' width={iconSizes.size12} height={iconSizes.size12} />,
},
{
id: 3,
title: i18n.translate('screens.settings.support.label'),
onPress: onPressSupport,
accessibilityLabel: i18n.translate('screens.settings.support.accessibility.label'),
accessibilityHint: i18n.translate('screens.settings.support.accessibility.hint'),
icon: <Icon name='external_link' width={iconSizes.size12} height={iconSizes.size12} />,
},
{
id: 4,
title: i18n.translate('screens.settings.legal_information.label'),
onPress: onPressLegalInformation,
accessibilityLabel: i18n.translate('screens.settings.legal_information.accessibility.label'),
accessibilityHint: i18n.translate('screens.settings.legal_information.accessibility.hint'),
},
];
if (!Configuration.RELEASE) {
bottomItems.push(
{
id: 5,
title: i18n.translate('screens.settings.debug.label'),
onPress: onPressDebug,
accessibilityLabel: i18n.translate('screens.settings.debug.accessibility.label'),
accessibilityHint: i18n.translate('screens.settings.debug.accessibility.hint'),
},
);
}
return (
<TopComponent style={memoizedStyle.container}>
<Layout style={memoizedStyle.layoutContainer}>
<View style={memoizedStyle.header}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.settings.actions.back.accessibility.label')}
accessibilityHint={i18n.translate('screens.settings.actions.back.accessibility.hint')}
>
<Icon name='close' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
</View>
<View style={memoizedStyle.itemsContainer}>
<Text size='small' weight='bold' textColor={colors.settingsLabelTextColor} style={memoizedStyle.version}>{i18n.translate('screens.settings.version', { version: appVersion, build: appBuild })}</Text>
<List items={topItems} style={memoizedStyle.topItems} />
<List items={bottomItems} style={memoizedStyle.bottomItems} />
</View>
</Layout>
<View style={memoizedStyle.imagesContainer}>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #16
Source File: MainScreen.js From filen-mobile with GNU Affero General Public License v3.0 | 4 votes |
MainScreen = memo(({ navigation, route }) => {
const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
const [userId, setUserId] = useMMKVNumber("userId", storage)
const [routeURL, setRouteURL] = useState(useCallback(getRouteURL(route)))
const cachedItemsRef = useRef(storage.getString("loadItemsCache:" + routeURL)).current
const cachedItemsParsed = useRef(typeof cachedItemsRef == "string" ? JSON.parse(cachedItemsRef) : []).current
const [items, setItems] = useState(Array.isArray(cachedItemsParsed) ? cachedItemsParsed.filter(item => item !== null && typeof item.uuid == "string") : [])
const [searchTerm, setSearchTerm] = useState("")
const [loadDone, setLoadDone] = useState(typeof cachedItemsRef !== "undefined" ? true : false)
const setNavigation = useStore(useCallback(state => state.setNavigation))
const setRoute = useStore(useCallback(state => state.setRoute))
const [masterKeys, setMasterKeys] = useState(useCallback(getMasterKeys()))
const isMounted = useMountedState()
const setCurrentActionSheetItem = useStore(useCallback(state => state.setCurrentActionSheetItem))
const setCurrentItems = useStore(useCallback(state => state.setCurrentItems))
const itemsRef = useRef([])
const setItemsSelectedCount = useStore(useCallback(state => state.setItemsSelectedCount))
const setInsets = useStore(useCallback(state => state.setInsets))
const insets = useSafeAreaInsets()
const [progress, setProgress] = useState({ itemsDone: 0, totalItems: 1 })
const selectedCountRef = useRef(0)
const setIsDeviceReady = useStore(useCallback(state => state.setIsDeviceReady))
const [itemsBeforeSearch, setItemsBeforeSearch] = useState([])
const [photosGridSize, setPhotosGridSize] = useMMKVNumber("photosGridSize", storage)
const bottomBarHeight = useStore(useCallback(state => state.bottomBarHeight))
const topBarHeight = useStore(useCallback(state => state.topBarHeight))
const contentHeight = useStore(useCallback(state => state.contentHeight))
const [photosRange, setPhotosRange] = useMMKVString("photosRange:" + userId, storage)
const netInfo = useStore(useCallback(state => state.netInfo))
const itemsSortBy = useStore(useCallback(state => state.itemsSortBy))
const [initialized, setInitialized] = useState(false)
const isFocused = useIsFocused()
const updateItemThumbnail = useCallback((item, path) => {
if(typeof path !== "string"){
return false
}
if(path.length < 4){
return false
}
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == item.uuid && typeof mapItem.thumbnail == "undefined" ? {...mapItem, thumbnail: item.uuid + ".jpg" } : mapItem))
}
})
const selectItem = useCallback((item) => {
if(getRouteURL(route).indexOf("photos") !== -1){
if(calcPhotosGridSize(photosGridSize) >= 6){
return false
}
}
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == item.uuid ? {...mapItem, selected: true} : mapItem))
}
})
const unselectItem = useCallback((item) => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == item.uuid ? {...mapItem, selected: false} : mapItem))
}
})
const unselectAllItems = useCallback(() => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.selected ? {...mapItem, selected: false} : mapItem))
}
})
const selectAllItems = useCallback(() => {
if(getRouteURL(route).indexOf("photos") !== -1){
if(calcPhotosGridSize(photosGridSize) >= 6){
return false
}
}
if(isMounted()){
setItems(items => items.map(mapItem => !mapItem.selected ? {...mapItem, selected: true} : mapItem))
}
})
const removeItem = useCallback((uuid) => {
if(isMounted()){
setItems(items => items.filter(mapItem => mapItem.uuid !== uuid && mapItem))
}
})
const markOffline = useCallback((uuid, value) => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == uuid ? {...mapItem, offline: value} : mapItem))
}
})
const markFavorite = useCallback((uuid, value) => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == uuid ? {...mapItem, favorited: value} : mapItem))
}
})
const changeFolderColor = useCallback((uuid, color) => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == uuid && mapItem.type == "folder" ? {...mapItem, color} : mapItem))
}
})
const changeItemName = useCallback((uuid, name) => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == uuid ? {...mapItem, name} : mapItem))
}
})
const addItem = useCallback((item, parent) => {
const currentParent = getParent(route)
if(isMounted() && (currentParent == parent || (item.offline && parent == "offline"))){
setItems(items => sortItems({ items: [...items, item], passedRoute: route }))
}
})
const changeWholeItem = useCallback((item, uuid) => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == uuid ? item : mapItem))
}
})
const reloadList = useCallback((parent) => {
const currentParent = getParent(route)
if(isMounted() && currentParent == parent){
fetchItemList({ bypassCache: true, callStack: 1 })
}
})
const updateFolderSize = useCallback((uuid, size) => {
if(isMounted()){
setItems(items => items.map(mapItem => mapItem.uuid == uuid && mapItem.type == "folder" ? {...mapItem, size} : mapItem))
}
})
useEffect(() => {
if(isMounted() && initialized){
if(searchTerm.length == 0){
if(itemsBeforeSearch.length > 0){
setItems(itemsBeforeSearch)
setItemsBeforeSearch([])
}
}
else{
if(itemsBeforeSearch.length == 0){
setItemsBeforeSearch(items)
var filtered = items.filter(item => item.name.toLowerCase().trim().indexOf(searchTerm.toLowerCase().trim()) !== -1 && item)
}
else{
var filtered = itemsBeforeSearch.filter(item => item.name.toLowerCase().trim().indexOf(searchTerm.toLowerCase().trim()) !== -1 && item)
}
setItems(filtered)
}
}
}, [searchTerm])
useEffect(() => {
if(isMounted() && initialized){
const sorted = sortItems({ items, passedRoute: route })
setItems(sorted)
}
}, [itemsSortBy])
useEffect(() => {
if(isFocused){
if(Array.isArray(items) && items.length > 0){
setCurrentItems(items)
itemsRef.current = items
global.items = items
const selected = items.filter(item => item.selected).length
selectedCountRef.current = selected
setItemsSelectedCount(selectedCountRef.current)
}
else{
setCurrentItems([])
itemsRef.current = []
global.items = []
setItemsSelectedCount(0)
}
global.setItems = setItems
}
}, [items, isFocused])
const fetchItemList = useCallback(({ bypassCache = false, callStack = 0, loadFolderSizes = false }) => {
return new Promise((resolve, reject) => {
loadItems({
parent: getParent(route),
setItems,
masterKeys,
setLoadDone,
navigation,
isMounted,
bypassCache,
route,
setProgress,
callStack,
loadFolderSizes
}).then(resolve).catch(reject)
})
})
useEffect(() => {
setNavigation(navigation)
setRoute(route)
setInsets(insets)
fetchItemList({ bypassCache: false, callStack: 0, loadFolderSizes: false }).catch((err) => console.log(err))
global.fetchItemList = fetchItemList
const deviceListener = DeviceEventEmitter.addListener("event", (data) => {
const navigationRoutes = navigation.getState().routes
const isListenerActive = typeof navigationRoutes == "object" ? (navigationRoutes[navigationRoutes.length - 1].key == route.key) : false
if(data.type == "thumbnail-generated"){
updateItemThumbnail(data.data, data.data.path)
}
else if(data.type == "item-onpress" && isListenerActive){
if(data.data.selected){
unselectItem(data.data)
}
else{
if(selectedCountRef.current > 0){
selectItem(data.data)
}
else{
global.currentReceiverId = data.data.receiverId
try{
const currentRouteURL = getRouteURL(route)
if(typeof currentRouteURL == "string"){
if(data.data.type == "folder" && currentRouteURL.indexOf("trash") == -1){
navigationAnimation({ enable: true }).then(() => {
navigation.dispatch(StackActions.push("MainScreen", {
parent: currentRouteURL + "/" + data.data.uuid
}))
})
}
else{
previewItem({ item: data.data, navigation })
}
}
else{
console.log("route url !== string: ", currentRouteURL)
}
}
catch(e){
console.log(e)
}
}
}
}
else if(data.type == "item-onlongpress" && isListenerActive){
selectItem(data.data)
}
else if(data.type == "open-item-actionsheet" && isListenerActive){
setCurrentActionSheetItem(data.data)
SheetManager.show("ItemActionSheet")
}
else if(data.type == "unselect-all-items" && isListenerActive){
unselectAllItems()
}
else if(data.type == "select-all-items" && isListenerActive){
selectAllItems()
}
else if(data.type == "select-item" && isListenerActive){
selectItem(data.data)
}
else if(data.type == "unselect-item" && isListenerActive){
unselectItem(data.data)
}
else if(data.type == "remove-item"){
removeItem(data.data.uuid)
}
else if(data.type == "add-item"){
addItem(data.data.item, data.data.parent)
}
else if(data.type == "mark-item-offline"){
if(!data.data.value && getRouteURL(route).indexOf("offline") !== -1){
removeItem(data.data.uuid)
}
else{
markOffline(data.data.uuid, data.data.value)
}
}
else if(data.type == "mark-item-favorite"){
if(!data.data.value && getRouteURL(route).indexOf("favorites") !== -1){
removeItem(data.data.uuid)
}
else{
markFavorite(data.data.uuid, data.data.value)
}
}
else if(data.type == "change-folder-color"){
changeFolderColor(data.data.uuid, data.data.color)
}
else if(data.type == "change-item-name"){
changeItemName(data.data.uuid, data.data.name)
}
else if(data.type == "change-whole-item"){
changeWholeItem(data.data.item, data.data.uuid)
}
else if(data.type == "reload-list"){
reloadList(data.data.parent)
}
else if(data.type == "remove-public-link"){
if(getRouteURL(route).indexOf("links") !== -1){
removeItem(data.data.uuid)
}
}
else if(data.type == "folder-size"){
updateFolderSize(data.data.uuid, data.data.size)
}
})
setIsDeviceReady(true)
setInitialized(true)
return () => {
deviceListener.remove()
setPhotosRange("all")
}
}, [])
return (
<View style={{
height: "100%",
width: "100%",
backgroundColor: darkMode ? "black" : "white"
}}>
<TopBar navigation={navigation} route={route} setLoadDone={setLoadDone} searchTerm={searchTerm} setSearchTerm={setSearchTerm} />
<View style={{
height: routeURL.indexOf("photos") !== -1 ? (contentHeight - 40 - bottomBarHeight + (Platform.OS == "android" ? 35 : 26)) : (contentHeight - topBarHeight - bottomBarHeight + 30)
}}>
<ItemList navigation={navigation} route={route} items={items} setItems={setItems} showLoader={!loadDone} loadDone={loadDone} searchTerm={searchTerm} isMounted={isMounted} fetchItemList={fetchItemList} progress={progress} setProgress={setProgress} />
</View>
</View>
)
})
Example #17
Source File: ItemList.js From filen-mobile with GNU Affero General Public License v3.0 | 4 votes |
ItemList = memo(({ navigation, route, items, showLoader, setItems, searchTerm, isMounted, fetchItemList, progress, setProgress, loadDone }) => {
const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
const [refreshing, setRefreshing] = useState(false)
const [itemViewMode, setItemViewMode] = useMMKVString("itemViewMode", storage)
const dimensions = { window: Dimensions.get("window"), screen: Dimensions.get("screen") }
const [lang, setLang] = useMMKVString("lang", storage)
const cameraUploadTotal = useStore(useCallback(state => state.cameraUploadTotal))
const cameraUploadUploaded = useStore(useCallback(state => state.cameraUploadUploaded))
const [userId, setUserId] = useMMKVNumber("userId", storage)
const [cameraUploadEnabled, setCameraUploadEnabled] = useMMKVBoolean("cameraUploadEnabled:" + userId, storage)
const [scrollDate, setScrollDate] = useState(Array.isArray(items) && items.length > 0 ? calcCameraUploadCurrentDate(items[0].lastModified, items[items.length - 1].lastModified, lang) : "")
const [photosGridSize, setPhotosGridSize] = useMMKVNumber("photosGridSize", storage)
const [hideThumbnails, setHideThumbnails] = useMMKVBoolean("hideThumbnails:" + userId, storage)
const [hideFileNames, setHideFileNames] = useMMKVBoolean("hideFileNames:" + userId, storage)
const [hideSizes, setHideSizes] = useMMKVBoolean("hideSizes:" + userId, storage)
const [photosRange, setPhotosRange] = useMMKVString("photosRange:" + userId, storage)
const itemListRef = useRef()
const [routeURL, setRouteURL] = useState(useCallback(getRouteURL(route)))
const netInfo = useStore(useCallback(state => state.netInfo))
const [scrollIndex, setScrollIndex] = useState(0)
const [currentItems, setCurrentItems] = useState([])
const insets = useSafeAreaInsets()
const [onlyWifiUploads, setOnlyWifiUploads] = useMMKVBoolean("onlyWifiUploads:" + userId, storage)
const generateItemsForItemList = useCallback((items, range, lang = "en") => {
range = normalizePhotosRange(range)
if(range == "all"){
return items
}
let sortedItems = []
if(range == "years"){
const occupied = {}
for(let i = 0; i < items.length; i++){
const itemDate = new Date(items[i].lastModified * 1000)
const itemYear = itemDate.getFullYear()
const occKey = itemYear
if(typeof occupied[occKey] == "undefined"){
occupied[occKey] = {
...items[i],
title: itemYear,
remainingItems: 0,
including: []
}
}
occupied[occKey].remainingItems = occupied[occKey].remainingItems + 1
occupied[occKey].including.push(items[i].uuid)
}
for(let prop in occupied){
sortedItems.push(occupied[prop])
}
sortedItems = sortedItems.reverse()
}
else if(range == "months"){
const occupied = {}
for(let i = 0; i < items.length; i++){
const itemDate = new Date(items[i].lastModified * 1000)
const itemYear = itemDate.getFullYear()
const itemMonth = itemDate.getMonth()
const occKey = itemYear + ":" + itemMonth
if(typeof occupied[occKey] == "undefined"){
occupied[occKey] = {
...items[i],
title: i18n(lang, "month_" + itemMonth) + " " + itemYear,
remainingItems: 0,
including: []
}
}
occupied[occKey].remainingItems = occupied[occKey].remainingItems + 1
occupied[occKey].including.push(items[i].uuid)
}
for(let prop in occupied){
sortedItems.push(occupied[prop])
}
}
else if(range == "days"){
const occupied = {}
for(let i = 0; i < items.length; i++){
const itemDate = new Date(items[i].lastModified * 1000)
const itemYear = itemDate.getFullYear()
const itemMonth = itemDate.getMonth()
const itemDay = itemDate.getDate()
const occKey = itemYear + ":" + itemMonth + ":" + itemDay
if(typeof occupied[occKey] == "undefined"){
occupied[occKey] = {
...items[i],
title: itemDay + ". " + i18n(lang, "monthShort_" + itemMonth) + " " + itemYear,
remainingItems: 0,
including: []
}
}
occupied[occKey].remainingItems = occupied[occKey].remainingItems + 1
occupied[occKey].including.push(items[i].uuid)
}
for(let prop in occupied){
sortedItems.push(occupied[prop])
}
}
return sortedItems
}, [items, photosRange, lang])
const getThumbnail = useCallback(({ item }) => {
if(item.type == "file"){
if(canCompressThumbnail(getFileExt(item.name))){
if(typeof item.thumbnail !== "string"){
DeviceEventEmitter.emit("event", {
type: "generate-thumbnail",
item
})
}
else{
//DeviceEventEmitter.emit("event", {
// type: "check-thumbnail",
// item
//})
}
}
}
})
const onViewableItemsChangedRef = useRef(useCallback(({ viewableItems }) => {
if(typeof viewableItems[0] == "object"){
if(typeof viewableItems[0].index == "number"){
setScrollIndex(viewableItems[0].index >= 0 ? viewableItems[0].index : 0)
}
}
const visible = {}
for(let i = 0; i < viewableItems.length; i++){
let item = viewableItems[i].item
visible[item.uuid] = true
global.visibleItems[item.uuid] = true
getThumbnail({ item })
}
if(typeof viewableItems[0] == "object" && typeof viewableItems[viewableItems.length - 1] == "object" && routeURL.indexOf("photos") !== -1){
setScrollDate(calcCameraUploadCurrentDate(viewableItems[0].item.lastModified, viewableItems[viewableItems.length - 1].item.lastModified, lang))
}
for(let prop in global.visibleItems){
if(typeof visible[prop] !== "undefined"){
global.visibleItems[prop] = true
}
else{
delete global.visibleItems[prop]
}
}
}))
const viewabilityConfigRef = useRef({
minimumViewTime: 0,
viewAreaCoveragePercentThreshold: 0
})
const photosRangeItemClick = useCallback((item) => {
const currentRangeSelection = normalizePhotosRange(photosRange)
let nextRangeSelection = "all"
if(currentRangeSelection == "years"){
nextRangeSelection = "months"
}
else if(currentRangeSelection == "months"){
nextRangeSelection = "days"
}
else if(currentRangeSelection == "days"){
nextRangeSelection = "all"
}
else{
nextRangeSelection = "all"
}
const itemsForIndexLoop = generateItemsForItemList(items, nextRangeSelection, lang)
let scrollToIndex = 0
for(let i = 0; i < itemsForIndexLoop.length; i++){
if(nextRangeSelection == "all"){
if(itemsForIndexLoop[i].uuid == item.uuid){
scrollToIndex = i
}
}
else{
if(itemsForIndexLoop[i].including.includes(item.uuid)){
scrollToIndex = i
}
}
}
setScrollIndex(scrollToIndex >= 0 && scrollToIndex <= itemsForIndexLoop.length ? scrollToIndex : 0)
setPhotosRange(nextRangeSelection)
})
const getInitialScrollIndex = useCallback(() => {
const range = normalizePhotosRange(photosRange)
const gridSize = calcPhotosGridSize(photosGridSize)
const viewMode = routeURL.indexOf("photos") !== -1 ? "photos" : itemViewMode
const itemsLength = currentItems.length > 0 ? currentItems.length : items.length
if(viewMode == "list"){
return scrollIndex >= 0 && scrollIndex <= itemsLength ? scrollIndex : 0
}
if(range == "all"){
const calcedIndex = Math.floor(scrollIndex / gridSize)
return calcedIndex >= 0 && calcedIndex <= itemsLength ? calcedIndex : 0
}
else{
return scrollIndex >= 0 && scrollIndex <= itemsLength ? scrollIndex : 0
}
})
const renderItem = useCallback(({ item, index, viewMode }) => {
if(viewMode == "photos"){
if(normalizePhotosRange(photosRange) !== "all"){
return (
<PhotosRangeItem item={item} index={index} darkMode={darkMode} selected={item.selected} thumbnail={item.thumbnail} name={item.name} size={item.size} color={item.color} favorited={item.favorited} offline={item.offline} photosGridSize={photosGridSize} hideFileNames={hideFileNames} hideThumbnails={hideThumbnails} lang={lang} dimensions={dimensions} hideSizes={hideSizes} photosRange={normalizePhotosRange(photosRange)} photosRangeItemClick={photosRangeItemClick} insets={insets} />
)
}
return (
<PhotosItem item={item} index={index} darkMode={darkMode} selected={item.selected} thumbnail={item.thumbnail} name={item.name} size={item.size} color={item.color} favorited={item.favorited} offline={item.offline} photosGridSize={photosGridSize} hideFileNames={hideFileNames} hideThumbnails={hideThumbnails} lang={lang} dimensions={dimensions} hideSizes={hideSizes} insets={insets} />
)
}
if(viewMode == "grid"){
return (
<GridItem item={item} index={index} darkMode={darkMode} selected={item.selected} thumbnail={item.thumbnail} name={item.name} size={item.size} color={item.color} favorited={item.favorited} offline={item.offline} hideFileNames={hideFileNames} hideThumbnails={hideThumbnails} lang={lang} dimensions={dimensions} hideSizes={hideSizes} insets={insets} />
)
}
return (
<ListItem item={item} index={index} darkMode={darkMode} selected={item.selected} thumbnail={item.thumbnail} name={item.name} size={item.size} color={item.color} favorited={item.favorited} offline={item.offline} hideFileNames={hideFileNames} hideThumbnails={hideThumbnails} lang={lang} dimensions={dimensions} hideSizes={hideSizes} insets={insets} />
)
})
useEffect(() => {
setCurrentItems(generateItemsForItemList(items, normalizePhotosRange(photosRange), lang))
}, [items, photosRange, lang])
useEffect(() => {
if(items.length > 0){
const max = 32
for(let i = 0; i < items.length; i++){
if(i < max){
global.visibleItems[items[i].uuid] = true
getThumbnail({ item: items[i] })
}
}
}
}, [items, itemViewMode])
useEffect(() => {
if(calcPhotosGridSize(photosGridSize) >= 6){
DeviceEventEmitter.emit("event", {
type: "unselect-all-items"
})
}
}, [photosGridSize])
useEffect(() => {
items.forEach(item => {
if(item.type == "folder"){
getFolderSizeFromCache({ folder: item, routeURL, load: true })
}
})
}, [items])
return (
<View style={{
width: "100%",
height: "100%",
paddingLeft: itemViewMode == "grid" && routeURL.indexOf("photos") == -1 ? 15 : 0,
paddingRight: itemViewMode == "grid" && routeURL.indexOf("photos") == -1 ? 15 : 0
}}>
{
routeURL.indexOf("photos") !== -1 && (
<>
<View style={{
paddingBottom: 10,
paddingTop: 5,
borderBottomColor: darkMode ? "#111111" : "gray",
//borderBottomWidth: items.length > 0 ? 0 : 1,
borderBottomWidth: 0,
marginBottom: 3,
height: 35
}}>
{
cameraUploadEnabled ? (
<View style={{
flexDirection: "row",
justifyContent: "flex-start",
paddingLeft: 15,
paddingRight: 15
}}>
{
netInfo.isConnected && netInfo.isInternetReachable ? onlyWifiUploads && netInfo.type !== "wifi" ? (
<>
<Ionicon name="wifi-outline" size={20} color={"gray"} />
<Text style={{
marginLeft: 10,
color: "gray",
paddingTop: Platform.OS == "ios" ? 2 : 1
}}>
{i18n(lang, "onlyWifiUploads")}
</Text>
</>
) : cameraUploadTotal > 0 ? cameraUploadTotal > cameraUploadUploaded ? (
<>
<ActivityIndicator color={darkMode ? "white" : "black"} size="small" />
<Text style={{
marginLeft: 10,
color: "gray",
paddingTop: Platform.OS == "ios" ? 2 : 1
}}>
{i18n(lang, "cameraUploadProgress", true, ["__TOTAL__", "__UPLOADED__"], [cameraUploadTotal, cameraUploadUploaded])}
</Text>
</>
) : (
<>
<Ionicon name="checkmark-done-circle-outline" size={20} color="green" />
<Text style={{
marginLeft: 10,
color: "gray",
paddingTop: Platform.OS == "ios" ? 2 : 1
}}>
{i18n(lang, "cameraUploadEverythingUploaded")}
</Text>
</>
) : (
<>
<ActivityIndicator color={darkMode ? "white" : "black"} size="small" />
<Text style={{
marginLeft: 10,
color: "gray",
paddingTop: Platform.OS == "ios" ? 2 : 1
}}>
{i18n(lang, "cameraUploadFetchingAssetsFromLocal")}
</Text>
</>
) : (
<>
<Ionicon name="wifi-outline" size={20} color={"gray"} />
<Text style={{
marginLeft: 10,
color: "gray",
paddingTop: Platform.OS == "ios" ? 2 : 1
}}>
{i18n(lang, "deviceOffline")}
</Text>
</>
)
}
</View>
) : (
<View style={{
flexDirection: "row",
justifyContent: "space-between",
paddingLeft: 5,
paddingRight: 15
}}>
<Text style={{
marginLeft: 10,
color: "gray"
}}>
{i18n(lang, "cameraUploadNotEnabled")}
</Text>
{
netInfo.isConnected && netInfo.isInternetReachable && (
<TouchableOpacity onPress={() => {
navigationAnimation({ enable: true }).then(() => {
navigation.dispatch(StackActions.push("CameraUploadScreen"))
})
}}>
<Text style={{
color: "#0A84FF",
fontWeight: "bold"
}}>
{i18n(lang, "enable")}
</Text>
</TouchableOpacity>
)
}
</View>
)
}
</View>
{
scrollDate.length > 0 && items.length > 0 && normalizePhotosRange(photosRange) == "all" && (
<View style={{
backgroundColor: darkMode ? "rgba(34, 34, 34, 0.6)" : "rgba(128, 128, 128, 0.6)",
width: "auto",
height: "auto",
borderRadius: 15,
position: "absolute",
marginTop: 50,
marginLeft: 15,
zIndex: 100,
paddingTop: 5,
paddingBottom: 5,
paddingLeft: 8,
paddingRight: 8
}} pointerEvents="box-none">
<Text style={{
color: "white",
fontSize: 15
}}>{scrollDate}</Text>
</View>
)
}
{
items.length > 0 && (
<>
{
normalizePhotosRange(photosRange) == "all" && (
<View style={{
backgroundColor: darkMode ? "rgba(34, 34, 34, 0.6)" : "rgba(128, 128, 128, 0.6)",
width: "auto",
height: "auto",
borderRadius: 15,
position: "absolute",
marginTop: 50,
zIndex: 100,
paddingTop: 5,
paddingBottom: 5,
paddingLeft: 8,
paddingRight: 8,
right: 15,
flexDirection: "row"
}}>
<TouchableOpacity onPress={() => {
let gridSize = calcPhotosGridSize(photosGridSize)
if(photosGridSize >= 10){
gridSize = 10
}
else{
gridSize = gridSize + 1
}
setPhotosGridSize(gridSize)
}}>
<Ionicon name="remove-outline" size={24} color={photosGridSize >= 10 ? "gray" : "white"} />
</TouchableOpacity>
<Text style={{
color: "gray",
fontSize: 17,
marginLeft: 5
}}>|</Text>
<TouchableOpacity style={{
marginLeft: 6
}} onPress={() => {
let gridSize = calcPhotosGridSize(photosGridSize)
if(photosGridSize <= 1){
gridSize = 1
}
else{
gridSize = gridSize - 1
}
setPhotosGridSize(gridSize)
}}>
<Ionicon name="add-outline" size={24} color={photosGridSize <= 1 ? "gray" : "white"} />
</TouchableOpacity>
</View>
)
}
<View style={{
backgroundColor: darkMode ? "rgba(34, 34, 34, 0.7)" : "rgba(128, 128, 128, 0.8)",
width: "auto",
height: "auto",
borderRadius: 15,
position: "absolute",
zIndex: 100,
alignSelf: "center",
flexDirection: "row",
bottom: 10,
paddingTop: 3,
paddingBottom: 3,
paddingLeft: 3,
paddingRight: 3
}}>
{
["years", "months", "days", "all"].map((key, index) => {
return (
<TouchableOpacity key={index} style={{
backgroundColor: normalizePhotosRange(photosRange) == key ? darkMode ? "gray" : "darkgray" : "transparent",
width: "auto",
height: "auto",
paddingTop: 5,
paddingBottom: 5,
paddingLeft: 10,
paddingRight: 10,
borderRadius: 15,
marginLeft: index == 0 ? 0 : 10
}} onPress={() => {
DeviceEventEmitter.emit("event", {
type: "unselect-all-items"
})
setScrollIndex(0)
setPhotosRange(key)
}}>
<Text style={{
color: "white"
}}>
{i18n(lang, "photosRange_" + key)}
</Text>
</TouchableOpacity>
)
})
}
</View>
</>
)
}
</>
)
}
<FlatList
data={generateItemsForItemList(items, normalizePhotosRange(photosRange), lang)}
key={routeURL.indexOf("photos") !== -1 ? "photos:" + (normalizePhotosRange(photosRange) == "all" ? calcPhotosGridSize(photosGridSize) : normalizePhotosRange(photosRange)) : itemViewMode == "grid" ? "grid" : "list"}
renderItem={({ item, index }) => {
return renderItem({ item, index, viewMode: routeURL.indexOf("photos") !== -1 ? "photos" : itemViewMode })
}}
keyExtractor={(item, index) => index.toString()}
windowSize={8}
initialNumToRender={32}
ref={itemListRef}
removeClippedSubviews={true}
initialScrollIndex={(currentItems.length > 0 ? currentItems.length : generateItemsForItemList(items, normalizePhotosRange(photosRange), lang).length) > 0 ? getInitialScrollIndex() : undefined}
numColumns={routeURL.indexOf("photos") !== -1 ? (normalizePhotosRange(photosRange) == "all" ? calcPhotosGridSize(photosGridSize) : 1) : itemViewMode == "grid" ? 2 : 1}
getItemLayout={(data, index) => ({
length: (routeURL.indexOf("photos") !== -1 ? (photosRange == "all" ? (Math.floor(dimensions.window.width / calcPhotosGridSize(photosGridSize))) : (Math.floor((dimensions.window.width - (insets.left + insets.right)) - 1.5))) : (itemViewMode == "grid" ? (Math.floor((dimensions.window.width - (insets.left + insets.right)) / 2) - 19 + 40) : (55))),
offset: (routeURL.indexOf("photos") !== -1 ? (photosRange == "all" ? (Math.floor(dimensions.window.width / calcPhotosGridSize(photosGridSize))) : (Math.floor((dimensions.window.width - (insets.left + insets.right)) - 1.5))) : (itemViewMode == "grid" ? (Math.floor((dimensions.window.width - (insets.left + insets.right)) / 2) - 19 + 40) : (55))) * index,
index
})}
ListEmptyComponent={() => {
return (
<View style={{
width: "100%",
height: Math.floor(dimensions.screen.height - 250),
justifyContent: "center",
alignItems: "center",
alignContent: "center"
}}>
{
!loadDone ? (
<View>
<ActivityIndicator color={darkMode ? "white" : "black"} size="small" />
</View>
) : (
<ListEmpty route={route} searchTerm={searchTerm} />
)
}
</View>
)
}}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={async () => {
if(!loadDone){
return false
}
setRefreshing(true)
if(typeof fetchItemList == "function"){
try{
await new Promise((resolve) => setTimeout(resolve, 500))
await fetchItemList({ bypassCache: true, callStack: 1, loadFolderSizes: true })
}
catch(e){
console.log(e)
}
setTimeout(() => {
if(items.length > 0){
items.forEach(item => {
if(item.type == "folder"){
getFolderSizeFromCache({ folder: item, routeURL, load: true })
}
})
}
}, 250)
setRefreshing(false)
}
}}
tintColor={darkMode ? "white" : "black"}
size="default"
/>
}
style={{
height: "100%",
width: "100%"
}}
onViewableItemsChanged={onViewableItemsChangedRef.current}
viewabilityConfig={viewabilityConfigRef.current}
/>
</View>
)
})
Example #18
Source File: PrivacyPolicy.js From stayaway-app with European Union Public License 1.2 | 4 votes |
export default function PrivacyPolicy(props) {
const {
onClose,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
return (
<TopComponent scrollable={false} style={memoizedStyle.container}>
<Layout style={memoizedStyle.layoutContainer} padding='top'>
<View style={memoizedStyle.header}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.privacy_policy.actions.back.accessibility.label')}
accessibilityHint={i18n.translate('screens.privacy_policy.actions.back.accessibility.hint')}
>
<Icon name='arrow' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
<Text size='xlarge' weight='bold' style={memoizedStyle.headerTitle}>{i18n.translate('screens.privacy_policy.title')}</Text>
</View>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={memoizedStyle.bodyContainer}
>
<Text size='xsmall' style={memoizedStyle.description}>{i18n.translate('screens.privacy_policy.description')}</Text>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.data_treatment.name')}</Text>
<View style={memoizedStyle.body}>
<View style={memoizedStyle.responsible}>
<Text size='small' weight='bold' style={memoizedStyle.subtitle}>{i18n.translate('screens.privacy_policy.data_treatment.responsible')}</Text>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.data_treatment.dgs.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.dgs.address')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.dgs.phone')}</Text>
</View>
<View style={memoizedStyle.subcontractors}>
<Text size='small' weight='bold' style={memoizedStyle.subtitle}>{i18n.translate('screens.privacy_policy.data_treatment.subcontractors')}</Text>
<View style={memoizedStyle.subcontractor}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.data_treatment.inesctec.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.inesctec.address')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.inesctec.phone')}</Text>
</View>
<View style={memoizedStyle.subcontractor}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.data_treatment.keyruptive.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.keyruptive.address')}</Text>
</View>
<View style={memoizedStyle.subcontractor}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.data_treatment.ubirider.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.ubirider.address')}</Text>
</View>
<View style={memoizedStyle.subcontractor}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.data_treatment.spms.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.spms.address')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.spms.phone')}</Text>
</View>
<View style={memoizedStyle.subcontractor}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.data_treatment.incm.name')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.incm.address')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_treatment.incm.phone')}</Text>
</View>
</View>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.purposes_of_personal_data_processing.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.purposes_of_personal_data_processing.body')}</Text>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.lawfulness_of_data_processing.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.lawfulness_of_data_processing.body')}</Text>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.body')}</Text>
<View style={memoizedStyle.data}>
<Text size='xsmall' weight='bold' style={memoizedStyle.dataTitle}>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_teks.title')}</Text>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.definition')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_teks.definition')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.purpose')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_teks.purpose')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.storage')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_teks.storage')}</Text>
</View>
</View>
<View style={memoizedStyle.data}>
<Text size='xsmall' weight='bold' style={memoizedStyle.dataTitle}>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_uui.title')}</Text>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.definition')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_uui.definition')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.purpose')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_uui.purpose')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.storage')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.pseudonymised_data_uui.storage')}</Text>
</View>
</View>
<View style={memoizedStyle.data}>
<Text size='xsmall' weight='bold' style={memoizedStyle.dataTitle}>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_teks.title')}</Text>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.definition')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_teks.definition')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.purpose')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_teks.purpose')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.storage')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_teks.storage')}</Text>
</View>
</View>
<View style={memoizedStyle.data}>
<Text size='xsmall' weight='bold' style={memoizedStyle.dataTitle}>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_info.title')}</Text>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.definition')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_info.definition')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.purpose')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_info.purpose')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.storage')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_info.storage')}</Text>
</View>
</View>
<View style={memoizedStyle.data}>
<Text size='xsmall' weight='bold' style={memoizedStyle.dataTitle}>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_symptoms.title')}</Text>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.definition')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_symptoms.definition')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.purpose')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_symptoms.purpose')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.storage')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.health_data_symptoms.storage')}</Text>
</View>
</View>
<View style={memoizedStyle.data}>
<Text size='xsmall' weight='bold' style={memoizedStyle.dataTitle}>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.ip_address.title')}</Text>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.definition')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.ip_address.definition')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.purpose')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.ip_address.purpose')}</Text>
</View>
<View style={memoizedStyle.label}>
<Text size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.labels.storage')}</Text>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.personal_data_and_storage_periods.ip_address.storage')}</Text>
</View>
</View>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.data_collecting_and_processing.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.data_collecting_and_processing.body')}</Text>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.gaen_api.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.gaen_api.body')}</Text>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.use_of_equipment_resources.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.use_of_equipment_resources.body')}</Text>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.rights_of_data_subjects.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.rights_of_data_subjects.body')}</Text>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.uninstalling_and_suspending_the_application.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.uninstalling_and_suspending_the_application.body')}</Text>
</View>
</View>
<View style={memoizedStyle.clause}>
<Text size='small' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.privacy_policy.changes_to_the_privacy_policy.name')}</Text>
<View style={memoizedStyle.body}>
<Text size='xsmall'>{i18n.translate('screens.privacy_policy.changes_to_the_privacy_policy.body')}</Text>
</View>
</View>
<Text textColor={colors.settingsLabelTextColor} size='xsmall' weight='bold'>{i18n.translate('screens.privacy_policy.last_review')}</Text>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
</ScrollView>
</Layout>
<View style={memoizedStyle.imagesContainer}>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #19
Source File: TechnicalSheet.js From stayaway-app with European Union Public License 1.2 | 4 votes |
export default function TechnicalSheet (props) {
const {
onPressCoordinator,
onPressISPUP,
onPressKeyruptive,
onPressUbirider,
onPressSPMS,
onClose,
} = props;
const insets = useSafeAreaInsets();
const { name, colors } = useTheme();
const memoizedStyle = useMemo(() => styles(colors, insets), [name, insets]);
return (
<TopComponent>
<Layout style={memoizedStyle.layoutContainer}>
<View style={memoizedStyle.header}>
<ButtonWrapper
onPress={onClose}
style={memoizedStyle.closeButton}
accessibilityLabel={i18n.translate('screens.technical_sheet.actions.back.accessibility.label')}
accessibilityHint={i18n.translate('screens.technical_sheet.actions.back.accessibility.hint')}
>
<Icon name='arrow' width={iconSizes.size24} height={iconSizes.size24} />
</ButtonWrapper>
<Text size='xlarge' weight='bold' style={memoizedStyle.title}>{i18n.translate('screens.technical_sheet.title')}</Text>
</View>
<View style={memoizedStyle.itemsContainer}>
<View style={memoizedStyle.coordinatorContainer}>
<Text size='small' weight='bold' textColor={colors.settingsLabelTextColor} style={memoizedStyle.itemLabel}>{i18n.translate('screens.technical_sheet.coordination')}</Text>
<ButtonWrapper
style={memoizedStyle.item}
onPress={onPressCoordinator}
accessibilityRole='link'
accessibilityLabel={i18n.translate('screens.technical_sheet.inesctec.accessibility.label')}
accessibilityHint={i18n.translate('screens.technical_sheet.inesctec.accessibility.hint')}
>
<Image source={getThemedImage('logo_inesctec', name)} />
</ButtonWrapper>
</View>
<View style={memoizedStyle.partnersContainer}>
<Text size='small' weight='bold' textColor={colors.settingsLabelTextColor} style={memoizedStyle.itemLabel}>{i18n.translate('screens.technical_sheet.partners')}</Text>
<View style={memoizedStyle.itemsRow}>
<ButtonWrapper
style={{
...memoizedStyle.item,
marginRight: sizes.size8,
}}
onPress={onPressISPUP}
accessibilityRole='link'
accessibilityLabel={i18n.translate('screens.technical_sheet.ispup.accessibility.label')}
accessibilityHint={i18n.translate('screens.technical_sheet.ispup.accessibility.hint')}
>
<Image source={getThemedImage('logo_ispup', name)} />
</ButtonWrapper>
<ButtonWrapper
style={memoizedStyle.item}
onPress={onPressKeyruptive}
accessibilityRole='link'
accessibilityLabel={i18n.translate('screens.technical_sheet.keyruptive.accessibility.label')}
accessibilityHint={i18n.translate('screens.technical_sheet.keyruptive.accessibility.hint')}
>
<Image source={getThemedImage('logo_keyruptive', name)} />
</ButtonWrapper>
</View>
<View style={memoizedStyle.itemsRow}>
<ButtonWrapper
style={{
...memoizedStyle.item,
marginRight: sizes.size8,
}}
onPress={onPressUbirider}
accessibilityRole='link'
accessibilityLabel={i18n.translate('screens.technical_sheet.ubirider.accessibility.label')}
accessibilityHint={i18n.translate('screens.technical_sheet.ubirider.accessibility.hint')}
>
<Image source={getThemedImage('logo_ubirider', name)} />
</ButtonWrapper>
<ButtonWrapper
style={memoizedStyle.item}
onPress={onPressSPMS}
accessibilityRole='link'
accessibilityLabel={i18n.translate('screens.technical_sheet.spms.accessibility.label')}
accessibilityHint={i18n.translate('screens.technical_sheet.spms.accessibility.hint')}
>
<Image source={getThemedImage('logo_spms', name)} />
</ButtonWrapper>
</View>
</View>
</View>
</Layout>
<View style={memoizedStyle.imagesContainer}>
<View style={memoizedStyle.sponsors}>
<Image source={getThemedImage('republica_portuguesa', name)} style={memoizedStyle.republicaPortuguesaImage} />
<Image source={getThemedImage('logo_dgs', name)} style={memoizedStyle.dgsImage} />
</View>
<Image source={getThemedImage('splash', name)} style={memoizedStyle.splashImage} />
</View>
</TopComponent>
);
}
Example #20
Source File: ImageViewerScreen.js From filen-mobile with GNU Affero General Public License v3.0 | 4 votes |
ImageViewerScreen = memo(({ navigation, route }) => {
const screenDimensions = Dimensions.get("screen")
const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
const [lang, setLang] = useMMKVString("lang", storage)
const [imagePreviewModalItems, setImagePreviewModalItems] = useState(route.params.items || [])
const [imagePreviewModalIndex, setImagePreviewModalIndex] = useState(route.params.index || 0)
const setCurrentActionSheetItem = useStore(useCallback(state => state.setCurrentActionSheetItem))
const [images, setImages] = useState({})
const [currentName, setCurrentName] = useState("")
const [isZooming, setIsZooming] = useState(false)
const [isSwiping, setIsSwiping] = useState(false)
const zoomLevel = useRef(minZoom)
const thumbnailListRef = useRef()
const listRef = useRef()
const [currentIndex, setCurrentIndex] = useState(imagePreviewModalIndex)
const [showControls, setShowControls] = useState(true)
const insets = useSafeAreaInsets()
const viewRefs = useRef({}).current
const isMounted = useMountedState()
const tapCount = useRef(0)
const tapTimer = useRef(undefined)
const [portrait, setPortrait] = useState(screenDimensions.height >= screenDimensions.width)
const didNavBack = useRef(false)
const currentImagePreviewDownloads = useRef({}).current
const setListScrollAgain = useRef(false)
const imageActionsContainerHeight = new Animated.Value(120)
const imageActionsVisible = useRef(false)
const loadImage = useCallback((image, index) => {
if(!isMounted()){
return false
}
zoomLevel.current = minZoom
setCurrentName(image.file.name)
setCurrentActionSheetItem(image.file)
setCurrentIndex(index)
thumbnailListRef?.current?.scrollToIndex({
animated: true,
index,
viewPosition: 0.5
})
if(setListScrollAgain.current){
setListScrollAgain.current = false
listRef?.current?.scrollToIndex({
animated: false,
index
})
}
const currentImages = {...images}
if(typeof currentImages[image.uuid] == "string"){
return false
}
if(typeof currentImagePreviewDownloads[image.uuid] !== "undefined"){
return false
}
currentImagePreviewDownloads[image.uuid] = true
downloadWholeFileFSStream({
file: image.file
}).then((path) => {
delete currentImagePreviewDownloads[image.uuid]
if(!isMounted()){
return false
}
generateItemThumbnail({
item: image.file,
skipInViewCheck: true,
callback: (err, thumbPath) => {
if(!isMounted()){
return false
}
if(!err && typeof thumbPath == "string"){
updateItemThumbnail(image.file, thumbPath)
}
return setImages(prev => ({
...prev,
[image.uuid]: path
}))
}
})
}).catch((err) => {
delete currentImagePreviewDownloads[image.uuid]
console.log(err)
return showToast({ message: err.toString() })
})
})
const onViewableItemsChangedRef = useRef(useCallback(({ viewableItems }) => {
const indexItem = viewableItems[viewableItems.length - 1]
if(typeof indexItem !== "object"){
return false
}
if(typeof indexItem.item !== "object"){
return false
}
loadImage(indexItem.item, indexItem.index)
}))
const updateItemThumbnail = useCallback((item, path) => {
if(typeof path !== "string"){
return false
}
if(path.length < 4){
return false
}
if(isMounted()){
setImagePreviewModalItems(prev => [...prev.map(mapItem => mapItem.file.uuid == item.uuid && typeof mapItem.thumbnail == "undefined" ? {...mapItem, thumbnail: item.uuid + ".jpg" } : mapItem)])
}
})
const viewabilityConfigRef = useRef({
minimumViewTime: 0,
viewAreaCoveragePercentThreshold: 95,
viewAreaCoveragePercentThreshold: 95,
waitForInteraction: false
})
useEffect(() => {
if(!isMounted()){
return false
}
setShowControls(isZooming)
}, [isZooming])
useEffect(() => {
if(imagePreviewModalItems.length == 0){
return navigation.goBack()
}
if(Platform.OS == "ios"){
setStatusBarStyle(true)
}
if(Platform.OS == "android"){
hideNavigationBar()
StatusBar.setHidden(true)
}
if(typeof imagePreviewModalItems[imagePreviewModalIndex] !== "undefined"){
setTimeout(() => {
loadImage(imagePreviewModalItems[imagePreviewModalIndex], imagePreviewModalIndex)
}, 50)
}
const dimensionsListener = Dimensions.addEventListener("change", ({ screen }) => {
if(!isMounted()){
return false
}
setPortrait(screen.height >= screen.width)
})
return () => {
dimensionsListener.remove()
if(Platform.OS == "ios"){
setStatusBarStyle(darkMode)
setTimeout(() => setStatusBarStyle(darkMode), 500)
setTimeout(() => setStatusBarStyle(darkMode), 1000)
}
if(Platform.OS == "android"){
showNavigationBar()
StatusBar.setHidden(false)
}
}
}, [])
const renderImage = useCallback((item, index) => {
const image = item
if(typeof image.thumbnail !== "string"){
return (
<View
key={image.uuid}
style={{
width: screenDimensions.width,
height: screenDimensions.height
}}
>
<ActivityIndicator size={"small"} color={"white"} style={{
margin: "auto",
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0
}} />
</View>
)
}
return (
<ReactNativeZoomableView
key={image.uuid}
ref={(ref) => viewRefs[image.uuid] = ref}
maxZoom={3}
minZoom={minZoom}
zoomStep={2}
initialZoom={minZoom}
bindToBorders={true}
contentWidth={screenDimensions.width}
contentHeight={screenDimensions.height}
style={{
width: screenDimensions.width,
height: screenDimensions.height
}}
onZoomBefore={(e, state, view) => {
setIsZooming(view.zoomLevel > 1)
zoomLevel.current = view.zoomLevel
}}
onZoomAfter={(e, state, view) => {
setIsZooming(view.zoomLevel > 1)
zoomLevel.current = view.zoomLevel
if(view.zoomLevel <= 1.05){
listRef?.current?.scrollToIndex({
animated: false,
index
})
thumbnailListRef?.current?.scrollToIndex({
animated: false,
index,
viewPosition: 0.5
})
}
}}
onShiftingBefore={(e, state, view) => {
setIsZooming(view.zoomLevel > 1)
zoomLevel.current = view.zoomLevel
}}
onShiftingAfter={(e, state, view) => {
setIsZooming(view.zoomLevel > 1)
if((view.distanceTop >= 50 || view.distanceBottom >= 50) && !didNavBack.current && zoomLevel.current <= 1 && !isSwiping && !isZooming){
didNavBack.current = true
navigation.goBack()
return true
}
zoomLevel.current = view.zoomLevel
}}
captureEvent={true}
>
<Pressable
onPress={() => {
if(isSwiping){
return false
}
tapCount.current += 1
if(tapCount.current >= 2){
if(zoomLevel.current >= 1.01){
viewRefs[image.uuid]?.zoomTo(1)
zoomLevel.current = 1
setIsZooming(false)
}
else{
viewRefs[image.uuid]?.zoomTo(2)
zoomLevel.current = 2
setIsZooming(true)
}
tapCount.current = 0
return clearTimeout(tapTimer.current)
}
clearTimeout(tapTimer.current)
tapTimer.current = setTimeout(() => {
if(tapCount.current >= 2){
if(zoomLevel.current >= 2){
viewRefs[image.uuid]?.zoomTo(1)
zoomLevel.current = 1
setIsZooming(false)
}
else{
viewRefs[image.uuid]?.zoomTo(2)
zoomLevel.current = 2
setIsZooming(true)
}
}
else{
setShowControls(prev => !prev)
}
tapCount.current = 0
}, 300)
}}
>
<>
<ImageBackground
source={{
uri: decodeURIComponent("file://" + THUMBNAIL_BASE_PATH + image.thumbnail)
}}
resizeMode="contain"
style={{
width: screenDimensions.width,
height: screenDimensions.height
}}
>
{
typeof images[image.uuid] == "string" && (
<Image
source={{
uri: decodeURIComponent(images[image.uuid].startsWith("file://") ? images[image.uuid] : "file://" + images[image.uuid])
}}
resizeMode="contain"
style={{
width: screenDimensions.width,
height: screenDimensions.height
}}
/>
)
}
</ImageBackground>
{
typeof images[image.uuid] !== "string" && (
<ActivityIndicator size={"small"} color={"white"} style={{
margin: "auto",
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0
}} />
)
}
</>
</Pressable>
</ReactNativeZoomableView>
)
})
const renderThumb = useCallback((item, index) => {
const image = item
return (
<View
style={{
width: 30,
height: 50
}}
>
<TouchableOpacity
key={image.uuid}
style={{
width: 30,
height: 50,
backgroundColor: "transparent",
flexDirection: "column",
justifyContent: "space-between",
alignItems: "center"
}}
onPress={async () => {
try{
await viewRefs[imagePreviewModalItems[currentIndex].uuid]?.zoomTo(1)
}
catch(e){
console.log(e)
}
setListScrollAgain.current = true
thumbnailListRef?.current?.scrollToIndex({
animated: false,
index,
viewPosition: 0.5
})
listRef?.current?.scrollToOffset({
animated: false,
offset: screenDimensions.width * index + 1
})
loadImage(imagePreviewModalItems[index], index)
}}
>
{
typeof image.thumbnail !== "string" ? (
<Image
source={getImageForItem(image.file)}
resizeMode="cover"
style={{
width: 25,
height: 35,
marginTop: 2.5,
marginLeft: 2.5
}}
/>
) : (
<Image
source={{
uri: decodeURIComponent("file://" + THUMBNAIL_BASE_PATH + image.thumbnail)
}}
resizeMode="cover"
style={{
width: 30,
height: 40
}}
/>
)
}
<View style={{
backgroundColor: currentIndex == index ? "gray" : "transparent",
width: 15,
height: 5,
borderRadius: 20
}}></View>
</TouchableOpacity>
</View>
)
})
return (
<View style={{
backgroundColor: "black",
height: screenDimensions.height,
width: screenDimensions.width,
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0
}}>
<View style={{
opacity: showControls ? 0 : 1,
flexDirection: "row",
height: "auto",
width: screenDimensions.width,
justifyContent: "space-between",
alignItems: "center",
position: "absolute",
top: 0,
zIndex: showControls ? 0 : 1000,
backgroundColor: "rgba(0, 0, 0, 0.6)",
paddingLeft: 10,
paddingRight: 15,
paddingTop: Platform.OS == "android" ? (insets.top + 5) : ((!portrait ? 10 : insets.top) + 5),
paddingBottom: 10,
marginTop: 0
}}>
<View style={{
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center"
}}>
<TouchableOpacity style={{
marginTop: Platform.OS == "android" ? 1 : 0,
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center"
}} hitSlop={{
top: 10,
left: 10,
bottom: 10,
right: 10
}} onPress={() => {
navigationAnimation({ enable: true }).then(() => {
navigation.goBack()
})
}}>
<Ionicon name="chevron-back" size={24} color={"white"}></Ionicon>
</TouchableOpacity>
<Text numberOfLines={1} style={{
color: "white",
width: "93%",
fontSize: 17,
paddingLeft: 10,
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center",
fontWeight: "bold"
}}>
{currentName}
</Text>
</View>
<View style={{
display: "none"
}}>
<TouchableOpacity style={{
marginTop: Platform.OS == "android" ? 1 : 0
}} hitSlop={{
top: 10,
left: 10,
bottom: 10,
right: 10
}} onPress={() => {
imageActionsVisible.current = !imageActionsVisible.current
Animated.timing( // Animate over time
imageActionsContainerHeight, // The animated value to drive, this would be a new Animated.Value(0) object.
{
toValue: imageActionsVisible.current ? 300 : 120, // Animate the value
duration: 100, // Make it take a while
useNativeDriver: false
}
).start()
}}>
<Ionicon name="ellipsis-horizontal-sharp" size={24} color={"white"}></Ionicon>
</TouchableOpacity>
</View>
</View>
<FlatList
style={{
position: "absolute",
width: screenDimensions.width,
height: screenDimensions.height,
zIndex: 10
}}
ref={listRef}
data={imagePreviewModalItems}
initialScrollIndex={currentIndex}
renderItem={({ item, index }) => {
return renderImage(item, index)
}}
key={portrait ? "portrait" : "landscape"}
extraData={portrait ? "portrait" : "landscape"}
keyExtractor={(item, index) => item.uuid}
windowSize={3}
initialNumToRender={1}
horizontal={true}
bounces={true}
getItemLayout={(data, index) => ({ length: screenDimensions.width, offset: screenDimensions.width * index, index })}
scrollEnabled={!isZooming}
pagingEnabled={true}
onViewableItemsChanged={onViewableItemsChangedRef?.current}
viewabilityConfig={viewabilityConfigRef?.current}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
onScrollBeginDrag={() => setIsSwiping(true)}
onScrollEndDrag={() => setIsSwiping(false)}
removeClippedSubviews={false}
/>
<Animated.View
style={{
position: "absolute",
bottom: -30,
width: screenDimensions.width,
height: imageActionsContainerHeight,
zIndex: showControls ? 0 : 10000,
backgroundColor: "rgba(0, 0, 0, 1)",
paddingTop: 1,
paddingBottom: insets.bottom + insets.top,
opacity: showControls ? 0 : 1,
paddingBottom: insets.bottom
}}
>
<FlatList
style={{
position: "absolute",
width: screenDimensions.width,
height: 120,
paddingTop: 3
}}
ref={thumbnailListRef}
data={imagePreviewModalItems}
renderItem={({ item, index }) => {
return renderThumb(item, index)
}}
getItemLayout={(data, index) => ({ length: 30, offset: 30 * index, index })}
keyExtractor={(item, index) => item.uuid}
horizontal={true}
scrollEnabled={true}
bounces={false}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
removeClippedSubviews={false}
/>
<View style={{
marginTop: 60,
borderTopColor: "gray",
borderTopWidth: 1,
opacity: 0
}}>
<View style={{
width: "100%",
height: 45,
flexDirection: "row",
justifyContent: "space-between",
borderBottomColor: "gray",
borderBottomWidth: 1,
paddingLeft: 15,
paddingRight: 15
}}>
<Text style={{
color: "white",
paddingTop: 12
}}>
{i18n(lang, "publicLinkEnabled")}
</Text>
<View style={{
paddingTop: Platform.OS == "ios" ? 6 : 8
}}>
</View>
</View>
</View>
</Animated.View>
</View>
)
})