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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
    )
})