react-native#Pressable JavaScript Examples

The following examples show how to use react-native#Pressable. 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: Progress.js    From lx-music-mobile with Apache License 2.0 6 votes vote down vote up
Progress = ({ progress, bufferedProgress, duration }) => {
  // const { progress } = usePlayTimeBuffer()
  const theme = useGetter('common', 'theme')
  // console.log(progress)
  const progressStr = progress + '%'

  return (
    <View style={styles.progress}>
      <View>
        <DefaultBar />
        <BufferedBar bufferedProgress={bufferedProgress} />
        <View style={{ ...styles.progressBar, backgroundColor: theme.secondary30, width: progressStr, position: 'absolute', left: 0, top: 0 }}>
          <Pressable style={{ ...styles.progressDot, backgroundColor: theme.secondary10 }}></Pressable>
        </View>
      </View>
      <PreassBar duration={duration} />
      {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */}
    </View>
  )
}
Example #2
Source File: Progress.js    From lx-music-mobile with Apache License 2.0 6 votes vote down vote up
PreassBar = memo(({ duration }) => {
  const { onLayout, ...layout } = useLayout()
  const setProgress = useDispatch('player', 'setProgress')
  const handlePress = event => {
    setProgress(event.nativeEvent.locationX / layout.width * duration)
  }

  return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} />
})
Example #3
Source File: Progress.js    From lx-music-mobile with Apache License 2.0 6 votes vote down vote up
Progress = ({ progress, bufferedProgress, duration }) => {
  // const { progress } = usePlayTimeBuffer()
  const theme = useGetter('common', 'theme')
  // console.log(progress)
  const progressStr = progress + '%'

  return (
    <View style={styles.progress}>
      <View>
        <DefaultBar />
        <BufferedBar bufferedProgress={bufferedProgress} />
        <View style={{ ...styles.progressBar, backgroundColor: theme.secondary30, width: progressStr, position: 'absolute', left: 0, top: 0 }}>
          <Pressable style={{ ...styles.progressDot, backgroundColor: theme.secondary10 }}></Pressable>
        </View>
      </View>
      <PreassBar duration={duration} />
      {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */}
    </View>
  )
}
Example #4
Source File: Progress.js    From lx-music-mobile with Apache License 2.0 6 votes vote down vote up
PreassBar = memo(({ duration }) => {
  const { onLayout, ...layout } = useLayout()
  const setProgress = useDispatch('player', 'setProgress')
  const handlePress = event => {
    setProgress(event.nativeEvent.locationX / layout.width * duration)
  }

  return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} />
})
Example #5
Source File: Modals.js    From filen-mobile with GNU Affero General Public License v3.0 6 votes vote down vote up
FullscreenLoadingModal = memo(() => {
    const fullscreenLoadingModalVisible = useStore(useCallback(state => state.fullscreenLoadingModalVisible))
    const setFullscreenLoadingModalVisible = useStore(useCallback(state => state.setFullscreenLoadingModalVisible))
    const setFullscreenLoadingModalDismissable = useStore(useCallback(state => state.setFullscreenLoadingModalDismissable))
    const fullscreenLoadingModalDismissable = useStore(useCallback(state => state.fullscreenLoadingModalDismissable))

    if(!fullscreenLoadingModalVisible){
        return null
    }

    return (
        <Pressable style={{
            position: "absolute",
            height: "100%",
            width: "100%",
            backgroundColor: "rgba(0, 0, 0, 0.4)",
            justifyContent: "center",
            alignItems: "center"
        }} onPress={() => {
            if(fullscreenLoadingModalDismissable){
                setFullscreenLoadingModalVisible(false)
                setFullscreenLoadingModalDismissable(false)
            }
        }}>
            <ActivityIndicator size={"small"} color="white" />
        </Pressable>
    )
})
Example #6
Source File: Progress.js    From lx-music-mobile with Apache License 2.0 6 votes vote down vote up
Progress = ({ progress, bufferedProgress, duration }) => {
  // const { progress } = usePlayTimeBuffer()
  const theme = useGetter('common', 'theme')
  // console.log(progress)
  const progressStr = progress + '%'

  return (
    <View style={styles.progress}>
      <View>
        <DefaultBar />
        <BufferedBar bufferedProgress={bufferedProgress} />
        <View style={{ ...styles.progressBar, backgroundColor: theme.secondary30, width: progressStr, position: 'absolute', left: 0, top: 0 }}>
          <Pressable style={{ ...styles.progressDot, backgroundColor: theme.secondary10 }}></Pressable>
        </View>
      </View>
      <PreassBar duration={duration} />
      {/* <View style={{ ...styles.progressBar, height: '100%', width: progressStr }}><Pressable style={styles.progressDot}></Pressable></View> */}
    </View>
  )
}
Example #7
Source File: Progress.js    From lx-music-mobile with Apache License 2.0 6 votes vote down vote up
PreassBar = memo(({ duration }) => {
  const { onLayout, ...layout } = useLayout()
  const setProgress = useDispatch('player', 'setProgress')
  const handlePress = event => {
    setProgress(event.nativeEvent.locationX / layout.width * duration)
  }

  return <Pressable onPress={handlePress} onLayout={onLayout} style={styles.pressBar} />
})
Example #8
Source File: index.js    From react-native-in-app-review with MIT License 6 votes vote down vote up
ReviewApp = () => {
  const {onReview} = useAppReview();
  return (
    <View style={styles.MainContainer}>
      <Text style={styles.CartExampleTxt}>Cart Page Example</Text>
      <View style={styles.containerBtn}>
        <Pressable
          testID={'RATE-ME'}
          onPress={onReview}
          style={styles.RateMeBtn}>
          <Text style={styles.RateMeTxt}>Checkout</Text>
        </Pressable>
      </View>
    </View>
  );
}
Example #9
Source File: Button.js    From lx-music-mobile with Apache License 2.0 6 votes vote down vote up
Btn = ({ ripple: propsRipple, children, disabled, style, ...props }, ref) => {
  const theme = useGetter('common', 'theme')
  const btnRef = useRef()
  const ripple = useMemo(() => ({
    color: theme.secondary30,
    ...(propsRipple || {}),
  }), [theme, propsRipple])

  useImperativeHandle(ref, () => ({
    measure(callback) {
      if (!btnRef.current) return
      btnRef.current.measure(callback)
    },
  }))

  return (
    <Pressable android_ripple={ripple} disabled={disabled} style={{ opacity: disabled ? 0.3 : 1, ...style }} {...props} ref={btnRef}>
      {children}
    </Pressable>
  )
}
Example #10
Source File: RenderItemCard.js    From rn-animation with MIT License 5 votes vote down vote up
AnimatedPressable = Animated.createAnimatedComponent(Pressable)
Example #11
Source File: Tabbar1.js    From rn-animation with MIT License 5 votes vote down vote up
render () {

    const backgroundColor = this.aniamte.interpolate({
      inputRange: listTab.map((_, index) => index),
      outputRange: listTab.map(item => item.color),
    });

    return (
      <Animated.View style={{
        flex: 1,
        backgroundColor,
      }}>
        <StatusBar barStyle={'light-content'}/>
        <SafeAreaView/>

        <Pressable
          style={{ marginHorizontal: MARGIN_wScale }}
          onPress={() => this.props.navigation.goBack()}>
          <BackArrowSvg
            size={wScale(25)}
            color={'#fff'}
          />
        </Pressable>

        <View style={{ flex: 1 }}/>

        <View style={{
          backgroundColor: '#fff',
          borderRadius: BORDER_RADIUS * 2,
          alignItems: 'center',
          width: SCREEN_WIDTH * 0.85,
          alignSelf: 'center',
        }}>

          <FlatList data={listTab}
                    contentContainerStyle={{ marginVertical: hScale(15) }}
                    scrollEnabled={false}
                    horizontal={true}
                    renderItem={this._renderItem}
                    extraData={this.state.indexSelected}
          />
        </View>

        <SafeAreaView/>

      </Animated.View>
    );
  }
Example #12
Source File: ProcessDownload1.js    From rn-animation with MIT License 5 votes vote down vote up
ProcessDownload1 = () => {
  const [isDownload, setDownload] = useState(false);

  const startAnimation = useSharedValue(0);

  const downloadAnimationStyle = useAnimatedStyle(() => {
    return {
      opacity: startAnimation.value,
    };
  });

  const btnAnimationStyle = useAnimatedStyle(() => {
    return {
      opacity: interpolate(startAnimation.value, [0, 1], [1, 0]),
    };
  });

  const start = useCallback(() => {
    setDownload(true);
  });

  return (
    <View
      style={{
        flex: 1,
        backgroundColor: Colors.primary.light,
      }}>
      <SafeAreaView style={{backgroundColor: Colors.accent.general}} />
      <Header title={'Process Download 1'} isColor={true} />

      <View
        style={[
          {
            flex: 1,
          },
          ComponentStyles.parentCenter,
        ]}>
        <Animated.View style={downloadAnimationStyle}>
          <Download
            timeProcess={TIME}
            isDownload={isDownload}
            setDownload={setDownload}
            cancel={() => {
              startAnimation.value = withTiming(0, {
                duration: 300,
              });
            }}
          />
        </Animated.View>
      </View>

      <Animated.View style={[{height: BUTTON_HEIGHT * 2}, btnAnimationStyle]}>
        <Pressable
          onPress={() => {
            startAnimation.value = withTiming(
              1,
              {
                duration: 300,
              },
              (isFinished) => {
                if (isFinished) {
                  runOnJS(start)();
                }
              },
            );
          }}
          style={styles.btnActive}>
          <Text style={[styles.uploadText, {color: '#fff'}]}>
            Create download
          </Text>
        </Pressable>
      </Animated.View>

      <SafeAreaView />
    </View>
  );
}
Example #13
Source File: Login1.js    From rn-animation with MIT License 5 votes vote down vote up
render () {
    return (
      <View style={styles.container}>
        {this._renderBackDrop()}

        {this._renderSquare()}

        <Animated.FlatList
          contentContainerStyle={{ marginBottom: MARGIN_hScale * 2 }}
          data={dummyData.listAnimal}
          horizontal={true}
          showsHorizontalScrollIndicator={false}
          pagingEnabled={true}
          renderItem={this._renderItem}
          keyExtractor={((item, index) => String(index))}
          scrollEventThrottle={16}
          onScroll={Animated.event(
            [{ nativeEvent: { contentOffset: { x: this.scrollX } } }],
            { useNativeDriver: false },
          )}

        />
        <View style={{
          flexDirection: 'row',
          marginBottom: HEADER_HEIGHT + MARGIN_hScale,
          justifyContent: 'center',
        }}>

          <Pressable style={styles.btnWrapper}
                     onPress={() => this.props.navigation.goBack()}
          >
            <Text style={styles.textWrapper}>
              Login
            </Text>
          </Pressable>

          <Pressable style={styles.btnWrapper}
                     onPress={() => this.props.navigation.goBack()}
          >
            <Text style={styles.textWrapper}>
              Create Account
            </Text>
          </Pressable>


        </View>
        <Indicator scrollX={this.scrollX}/>

      </View>
    );
  }
Example #14
Source File: CardView3Detial.js    From rn-animation with MIT License 5 votes vote down vote up
CardView3Detail = ({route, navigation}) => {
  return (
    <View>
      <SharedElement id={`itemPhoto.${route.params.item.key}`}>
        <Image
          source={route.params.item.source}
          style={[
            {
              width: SCREEN_WIDTH,
              height: SCREEN_HEIGHT,
            },
          ]}
        />
      </SharedElement>

      <View
        style={{
          position: 'absolute',
          top: 0,
          bottom: 0,
          left: 0,
          right: 0,
        }}>
        <SafeAreaView />

        <View
          style={{
            flexDirection: 'row',
            marginHorizontal: MARGIN_wScale,
            alignItems: 'center',
          }}>
          <Pressable onPress={() => navigation.goBack()}>
            <BackArrowSvg size={wScale(25)} color={Colors.secondary.light} />
          </Pressable>

          <Text
            style={{
              color: Colors.secondary.light,
              fontFamily: Fonts.ExtraBold,
              fontSize: fontScale(25),
              marginHorizontal: MARGIN_wScale,
            }}>
            {route.params.item.key}
          </Text>
        </View>
      </View>
    </View>
  );
}
Example #15
Source File: CardView1Detail.js    From rn-animation with MIT License 5 votes vote down vote up
render () {
    const { item } = this.props.route.params;

    devLog(item);
    return (
      <View style={styles.container}>
        <View style={{}}>
          <SharedElement
            id={`item.${item.key}.image`}
          >
            <Image source={item.source}
                   style={{
                     width: SCREEN_WIDTH,
                     height: SCREEN_HEIGHT,
                   }}
            />
          </SharedElement>
        </View>


        <View style={{
          marginHorizontal: MARGIN_wScale,
          position: 'absolute',
          top: 0,
          bottom: 0,
          left: 0,
          right: 0,
        }}>
          <SafeAreaView/>

          <Pressable onPress={() => this.props.navigation.goBack()}>
            <BackArrowSvg
              size={wScale(25)}
              color={'#fff'}
            />
          </Pressable>

          <View style={{ flex: 1 }}/>

          <SharedElement
            id={`item.${item.key}.text`}
          >
            <Text style={{
              fontSize: fontScale(50),
              color: Colors.accent.general,
              fontFamily: Fonts.ExtraBold,
            }}>
              {item.key}
            </Text>
          </SharedElement>
          <SafeAreaView/>
        </View>

      </View>
    );
  }
Example #16
Source File: BottomBar.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
BottomBar = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const currentRoutes = useStore(useCallback(state => state.currentRoutes))
    const [lang, setLang] = useMMKVString("lang", storage)
    const netInfo = useStore(useCallback(state => state.netInfo))
    const setBottomBarHeight = useStore(useCallback(state => state.setBottomBarHeight))
    const [userId, setUserId] = useMMKVNumber("userId", storage)
    const [defaultDriveOnly, setDefaultDriveOnly] = useMMKVBoolean("defaultDriveOnly:" + userId, storage)
    const [defaultDriveUUID, setDefaultDriveUUID] = useMMKVString("defaultDriveUUID:" + userId, storage)

    const parent = getParent(route)
    const routeURL = getRouteURL(route)
    const baseName = defaultDriveOnly ? defaultDriveUUID : "base"

    let currentScreenName = "MainScreen"
    let isRecentsScreen = false
    let isTrashScreen = false
    let isSharedScreen = false
    let isPhotosScreen = false
    let isFavoritesScreen = false
    let isBaseScreen = false
    let isOfflineScreen = false

    if(typeof currentRoutes == "object"){
        if(currentRoutes.length > 0){
            const currentRoute = currentRoutes[currentRoutes.length - 1]

            currentScreenName = currentRoute.name

            isRecentsScreen = (routeURL.indexOf("recents") !== -1)
            isTrashScreen = (routeURL.indexOf("trash") !== -1)
            isPhotosScreen = (routeURL.indexOf("photos") !== -1)
            isFavoritesScreen = (routeURL.indexOf("favorites") !== -1)
            isSharedScreen = ((routeURL.indexOf("shared-in") !== -1) || (routeURL.indexOf("shared-out") !== -1) || (routeURL.indexOf("links") !== -1))
            isBaseScreen = (routeURL.indexOf(baseName) !== -1)
            isOfflineScreen = (routeURL.indexOf("offline") !== -1)
        }
    }

    const canOpenBottomAddActionSheet = currentScreenName == "MainScreen"
        && !isOfflineScreen 
        && !isTrashScreen 
        && !isFavoritesScreen 
        && !isPhotosScreen 
        && !isRecentsScreen 
        && routeURL.indexOf("shared-in") == -1 
        && parent !== "shared-out" 
        && parent !== "links"

    const showCloud = isBaseScreen 
        && !isRecentsScreen 
        && !isTrashScreen 
        && !isSharedScreen 
        && currentScreenName !== "SettingsAccountScreen" 
        && currentScreenName !== "LanguageScreen" 
        && currentScreenName !== "SettingsAdvancedScreen" 
        && currentScreenName !== "CameraUploadScreen" 
        && currentScreenName !== "SettingsScreen" 
        && currentScreenName !== "TransfersScreen" 
        && currentScreenName !== "EventsScreen" 
        && currentScreenName !== "EventsInfoScreen"
        && currentScreenName !== "GDPRScreen"
        && currentScreenName !== "InviteScreen"
        && currentScreenName !== "TwoFactorScreen"
        && currentScreenName !== "ChangeEmailPasswordScreen"
    
    const showSettings = currentScreenName == "SettingsScreen" 
        || currentScreenName == "LanguageScreen" 
        || currentScreenName == "SettingsAccountScreen" 
        || currentScreenName == "SettingsAdvancedScreen" 
        || currentScreenName == "CameraUploadScreen" 
        || currentScreenName == "EventsScreen" 
        || currentScreenName == "EventsInfoScreen" 
        || isTrashScreen
        || currentScreenName == "GDPRScreen"
        || currentScreenName == "InviteScreen"
        || currentScreenName == "TwoFactorScreen"
        || currentScreenName == "ChangeEmailPasswordScreen"
    
    const showHome = isSharedScreen
        || isRecentsScreen 
        || isFavoritesScreen  
        || isOfflineScreen

    return (
        <View style={{
            paddingTop: 6,
            height: 80,
            flexDirection: "row",
            justifyContent: "space-between",
            borderTopColor: getColor(darkMode, "primaryBorder"),
            borderTopWidth: 1
        }} onLayout={(e) => setBottomBarHeight(e.nativeEvent.layout.height)}>
            <Pressable style={{
                alignItems: "center",
                width: "20%",
            }} onPress={() => {
                navigationAnimation({ enable: false }).then(() => {
                    navigation.current.dispatch(CommonActions.reset({
                        index: 0,
                        routes: [
                            {
                                name: "MainScreen",
                                params: {
                                    parent: "recents"
                                }
                            }
                        ]
                    }))
                })
            }}>
                <Ionicon name={showHome ? "home" : "home-outline"} size={22} color={showHome ? "#0A84FF" : (darkMode ? "gray" : "gray")} />
                <Text style={{
                    color: showHome ? "#0A84FF" : (darkMode ? "gray" : "gray"),
                    fontSize: 10,
                    marginTop: 3
                }}>{i18n(lang, "home")}</Text>
            </Pressable>
            <Pressable style={{
                alignItems: "center",
                width: "20%",
            }} onPress={() => {
                navigationAnimation({ enable: false }).then(() => {
                    navigation.current.dispatch(CommonActions.reset({
                        index: 0,
                        routes: [
                            {
                                name: "MainScreen",
                                params: {
                                    parent: (defaultDriveOnly ? defaultDriveUUID : "base")
                                }
                            }
                        ]
                    }))
                })
            }}>
                <Ionicon name={showCloud ? "cloud" : "cloud-outline"} size={22} color={showCloud ? "#0A84FF" : (darkMode ? "gray" : "gray")} />
                <Text style={{
                    color: showCloud ? "#0A84FF" : (darkMode ? "gray" : "gray"),
                    fontSize: 10,
                    marginTop: 3
                }}>{i18n(lang, "cloud")}</Text>
            </Pressable>
            <Pressable style={{
                alignItems: "center",
                width: "20%",
                paddingTop: 2
            }} onPress={() => {
                if(canOpenBottomAddActionSheet && netInfo.isConnected && netInfo.isInternetReachable){
                    SheetManager.show("BottomBarAddActionSheet")
                }
            }}>
                <Ionicon name={netInfo.isConnected && netInfo.isInternetReachable ? (canOpenBottomAddActionSheet ? "add-circle-outline" : "close-circle-outline") : "cloud-offline-outline"} size={30} color={netInfo.isConnected && netInfo.isInternetReachable && canOpenBottomAddActionSheet ? darkMode ? "white" : "gray" : darkMode ? "gray" : "lightgray"} />
            </Pressable>
            <Pressable style={{
                alignItems: "center",
                width: "20%"
            }} onPress={() => {
                navigationAnimation({ enable: false }).then(() => {
                    navigation.current.dispatch(CommonActions.reset({
                        index: 0,
                        routes: [
                            {
                                name: "MainScreen",
                                params: {
                                    parent: "photos"
                                }
                            }
                        ]
                    }))
                })
            }}>
                <Ionicon name={isPhotosScreen ? "image" : "image-outline"} size={22} color={isPhotosScreen ? "#0A84FF" : (darkMode ? "gray" : "gray")} />
                <Text style={{
                    color: isPhotosScreen ? "#0A84FF" : (darkMode ? "gray" : "gray"),
                    fontSize: 10,
                    marginTop: 3
                }}>{i18n(lang, "photos")}</Text>
            </Pressable>
            <Pressable style={{
                alignItems: "center",
                width: "20%",
            }} onPress={() => {
                navigationAnimation({ enable: false }).then(() => {
                    navigation.current.dispatch(CommonActions.reset({
                        index: 0,
                        routes: [
                            {
                                name: "SettingsScreen"
                            }
                        ]
                    }))
                })
            }}>
                <Ionicon name={showSettings ? "settings" : "settings-outline"} size={22} color={showSettings ? "#0A84FF" : (darkMode ? "gray" : "gray")} />
                <Text style={{
                    color: showSettings ? "#0A84FF" : (darkMode ? "gray" : "gray"),
                    fontSize: 10,
                    marginTop: 3
                }}>{i18n(lang, "settings")}</Text>
            </Pressable>
        </View>
    )
})
Example #17
Source File: Download.js    From rn-animation with MIT License 4 votes vote down vote up
Download = ({timeProcess, isDownload, setDownload, cancel}) => {
  const processing = useValue(0);

  const [percentDownload, setPercentDownload] = useState(0);
  const transformProcess = useSharedValue(0);

  const clock = new Clock();
  const downloading = useValue(DOWNLOAD_STATUS.PAUSED);

  useCode(() => {
    return call([processing], (process) => {
      const percent = Math.round((process / WIDTH_PROCESS) * 100);
      setPercentDownload(percent);
    });
  }, [processing]);

  // Control download status
  useCode(
    () =>
      block([
        set(
          downloading,
          isDownload ? DOWNLOAD_STATUS.PROCESS : DOWNLOAD_STATUS.PAUSED,
        ),
      ]),
    [isDownload],
  );

  // Control process animation download (PROCESS/PAUSED)
  useCode(
    () =>
      block([
        cond(eq(downloading, DOWNLOAD_STATUS.PROCESS), [
          runTiming(clock, processing, WIDTH_PROCESS, timeProcess),
        ]),
        cond(eq(downloading, DOWNLOAD_STATUS.PAUSED), [stopClock(clock)]),
        // cond(eq(processing, WIDTH_PROCESS), set(processing, 0)),
      ]),
    [],
  );

  return (
    <View style={styles.container}>
      <View style={styles.lineWrapper}>
        <Line transformProcess={transformProcess} />
      </View>

      <Animated.View
        style={[
          styles.processBg,
          {
            transform: [{translateX: processing}],
          },
        ]}
      />

      <View style={styles.processWrapper}>
        <View>
          <Text style={styles.uploadText}>Uploading 3 files</Text>

          <Text style={styles.percentText}>
            {`${percentDownload}% • ${(
              (timeProcess * (1 - percentDownload / 100)) /
              1000
            ).toFixed(0)} seconds left`}
          </Text>
        </View>

        <View />

        <Pressable
          onPress={() => {
            transformProcess.value = withTiming(isDownload ? 1 : 0, {
              duration: 500,
            });
            if (isDownload) {
              setDownload(false);
            } else {
              setDownload(true);
            }
          }}>
          <CircleIcon>
            <Ionicons
              name={isDownload ? 'pause' : 'play'}
              size={wScale(17)}
              color={'#fff'}
            />
          </CircleIcon>
        </Pressable>

        <Pressable
          onPress={() => {
            downloading.setValue(DOWNLOAD_STATUS.PAUSED);
            processing.setValue(0);
            setDownload(false);
            cancel();
          }}>
          <CircleIcon>
            <Fontisto name={'close-a'} size={wScale(12)} color={'#fff'} />
          </CircleIcon>
        </Pressable>

        {/*<AntDesign name={'arrowsalt'} size={wScale(20)}*/}
        {/*           color={Colors.primary.light}/>*/}
      </View>
    </View>
  );
}
Example #18
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 #19
Source File: TwoFactorScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
TwoFactorScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const [enabled, setEnabled] = useState(route.params.accountSettings.twoFactorEnabled == 1 ? true : false)
    const [accountSettings, setAccountSettings] = useState(route.params.accountSettings)
    const dimensions = useStore(useCallback(state => state.dimensions))
    const [twoFactorKey, setTwoFactorKey] = useState("")
    const setDisable2FATwoFactorDialogVisible = useStore(useCallback(state => state.setDisable2FATwoFactorDialogVisible))

    console.log(route.params)

    return (
        <KeyboardAvoidingView behavior="position">
            <View style={{
                flexDirection: "row",
                justifyContent: "flex-start",
                backgroundColor: darkMode ? "black" : "white"
            }}>
                <TouchableOpacity style={{
                    marginTop: Platform.OS == "ios" ? 17 : 4,
                    marginLeft: 15,
                }} onPress={() => navigation.goBack()}>
                    <Ionicon name="chevron-back" size={24} color={darkMode ? "white" : "black"}></Ionicon>
                </TouchableOpacity>
                <Text style={{
                    color: darkMode ? "white" : "black",
                    fontWeight: "bold",
                    fontSize: 24,
                    marginLeft: 10,
                    marginTop: Platform.OS == "ios" ? 15 : 0
                }}>
                    {i18n(lang, "twoFactorAuthentication")}
                </Text>
            </View>
            <View style={{
                height: "100%",
                width: "100%",
                backgroundColor: darkMode ? "black" : "white"
            }}>
                {
                    enabled ? (
                        <>
                            <SettingsGroup>
                                <SettingsButtonLinkHighlight onPress={() => {
                                    Alert.alert(i18n(lang, "disable2FA"), i18n(lang, "disable2FAInfo"), [
                                        {
                                            text: i18n(lang, "cancel"),
                                            onPress: () => {
                                                return false
                                            },
                                            style: "cancel"
                                        },
                                        {
                                            text: i18n(lang, "ok"),
                                            onPress: () => {
                                                Alert.alert(i18n(lang, "disable2FA"), i18n(lang, "areYouReallySure"), [
                                                    {
                                                        text: i18n(lang, "cancel"),
                                                        onPress: () => {
                                                            return false
                                                        },
                                                        style: "cancel"
                                                    },
                                                    {
                                                        text: i18n(lang, "ok"),
                                                        onPress: () => {
                                                            setDisable2FATwoFactorDialogVisible(true)
                                                        },
                                                        style: "default"
                                                    }
                                                ], {
                                                    cancelable: true
                                                })
                                            },
                                            style: "default"
                                        }
                                    ], {
                                        cancelable: true
                                    })
                                }} title={i18n(lang, "disable2FA")} />
                            </SettingsGroup>
                            <View style={{
                                width: "100%",
                                height: "auto",
                                paddingLeft: 8,
                                paddingRight: 8,
                                marginTop: 5
                            }}>
                                <View style={{
                                    width: "100%",
                                    height: "auto",
                                    flexDirection: "row",
                                    justifyContent: "space-between",
                                    paddingLeft: 10,
                                    paddingRight: 10,
                                    paddingTop: 10,
                                    paddingBottom: 10
                                }}>
                                    <View>
                                        <Text style={{
                                            color: "gray",
                                            fontSize: 11
                                        }}>
                                            {i18n(lang, "disable2FAInfo")}
                                        </Text>
                                    </View>
                                </View>
                            </View>
                        </>
                    ) : (
                        <>
                            <View style={{
                                backgroundColor: "white",
                                width: "100%",
                                height: dimensions.screen.width,
                                justifyContent: "center",
                                alignItems: "center",
                                marginTop: 10
                            }}>
                                <QRCode
                                    value={"otpauth://totp/" + encodeURIComponent("Filen") + ":" + encodeURIComponent(accountSettings.email) + "?secret=" + encodeURIComponent(accountSettings.twoFactorKey) + "&issuer=" + encodeURIComponent("Filen") + "&digits=6&period=30"}
                                    size={dimensions.screen.width - 60}
                                    backgroundColor="white"
                                />
                            </View>
                            <SettingsGroup>
                                <Pressable style={{
                                    width: "100%",
                                    height: "auto"
                                }}>
                                    <View style={{
                                        width: "100%",
                                        height: "auto",
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        paddingLeft: 10,
                                        paddingRight: 10,
                                        paddingTop: 10,
                                        paddingBottom: 10
                                    }}>
                                        <Text style={{
                                            color: darkMode ? "white" : "black",
                                            width: "70%"
                                        }} numberOfLines={1}>
                                            {accountSettings.twoFactorKey}
                                        </Text>
                                        <TouchableOpacity onPress={() => {
                                            Clipboard.setString(accountSettings.twoFactorKey)

                                            showToast({ message: i18n(lang, "copiedToClipboard") })
                                        }}>
                                            <Text style={{
                                                color: "#0A84FF"
                                            }}>
                                                {i18n(lang, "copy")}
                                            </Text>
                                       </TouchableOpacity>
                                    </View>
                                </Pressable>
                            </SettingsGroup>
                            <SettingsGroup>
                                <Pressable style={{
                                    width: "100%",
                                    height: "auto"
                                }}>
                                    <View style={{
                                        width: "100%",
                                        height: "auto",
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        paddingLeft: 10,
                                        paddingRight: 10,
                                        paddingTop: 10,
                                        paddingBottom: 10
                                    }}>
                                        <TextInput
                                            onChangeText={setTwoFactorKey}
                                            value={twoFactorKey}
                                            placeholder={i18n(lang, "twoFactorPlaceholder")}
                                            placeholderTextColor={"gray"}
                                            autoCapitalize="none"
                                            autoComplete="off"
                                            returnKeyType="done"
                                            autoCorrect={false}
                                            style={{
                                                height: 35,
                                                width: "80%",
                                                maxWidth: "80%",
                                                padding: 5,
                                                backgroundColor: darkMode ? "#222222" : "lightgray",
                                                color: "gray",
                                                borderRadius: 10,
                                                paddingLeft: 10,
                                                paddingRight: 10
                                            }}
                                        />
                                        <TouchableOpacity onPress={() => {
                                            const code = twoFactorKey.trim()

                                            if(code.length == 0){
                                                return false
                                            }

                                            useStore.setState({ fullscreenLoadingModalVisible: true })

                                            Keyboard.dismiss()

                                            enable2FA({ code }).then(() => {
                                                useStore.setState({ fullscreenLoadingModalVisible: false })

                                                showToast({ message: i18n(lang, "twoFactorEnabledSuccess") })

                                                navigationAnimation({ enable: false }).then(() => {
                                                    navigation.dispatch(CommonActions.reset({
                                                        index: 1,
                                                        routes: [
                                                            {
                                                                name: "SettingsScreen"
                                                            },
                                                            {
                                                                name: "SettingsAccountScreen"
                                                            }
                                                        ]
                                                    }))
                                                })
                                            }).catch((err) => {
                                                console.log(err)

                                                useStore.setState({ fullscreenLoadingModalVisible: false })

                                                showToast({ message: err.toString() })
                                            })
                                        }}>
                                            <Text style={{
                                                color: "#0A84FF",
                                                paddingTop: 7
                                            }}>
                                                {i18n(lang, "enable")}
                                            </Text>
                                       </TouchableOpacity>
                                    </View>
                                </Pressable>
                            </SettingsGroup>
                        </>
                    )
                }
            </View>
        </KeyboardAvoidingView>
    )
})
Example #20
Source File: SettingsScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
SettingsHeader = memo(({ navigation, route, navigationEnabled = true }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [userId, setUserId] = useMMKVNumber("userId", storage)
    const [email, setEmail] = useMMKVString("email", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const netInfo = useStore(useCallback(state => state.netInfo))
    const [userInfo, setUserInfo] = useMMKVObject("userInfo:" + userId, storage)
    const [userAvatarCached, setUserAvatarCached] = useMMKVString("userAvatarCached:" + userId, storage)

    const cacheUserAvatar = useCallback(() => {
        if(typeof userInfo !== "undefined"){
            if(userInfo.avatarURL.indexOf("https://down.") !== -1){
                const avatarName = getFilenameFromPath(userInfo.avatarURL)

                if(userAvatarCached !== avatarName){
                    hasStoragePermissions().then(() => {
                        getDownloadPath({ type: "misc" }).then(async (path) => {
                            const avatarPath = path + avatarName
        
                            try{
                                if((await RNFS.exists(avatarPath))){
                                    await RNFS.unlink(avatarPath)
                                }
                            }
                            catch(e){
                                //console.log(e)
                            }
        
                            RNFS.downloadFile({
                                fromUrl: userInfo.avatarURL,
                                toFile: avatarPath
                            }).promise.then(async () => {
                                try{
                                    if(typeof userAvatarCached == "string"){
                                        if(userAvatarCached.length > 4){
                                            if((await RNFS.exists(MISC_BASE_PATH + userAvatarCached))){
                                                await RNFS.unlink(MISC_BASE_PATH + userAvatarCached)
                                            }
                                        }
                                    }
                                }
                                catch(e){
                                    //console.log(e)
                                }

                                setUserAvatarCached(avatarName)
                            }).catch((err) => {
                                console.log(err)
                            })
                        }).catch((err) => {
                            console.log(err)
                        })
                    }).catch((err) => {
                        console.log(err)
                    })
                }
                else{
                    if(typeof userAvatarCached == "string"){
                        if(userAvatarCached.length > 4){
                            getDownloadPath({ type: "misc" }).then((path) => {
                                const avatarPath = path + userAvatarCached
            
                                RNFS.exists(avatarPath).then((exists) => {
                                    if(!exists){
                                        setUserAvatarCached("")
        
                                        setTimeout(() => {
                                            cacheUserAvatar()
                                        }, 500)
                                    }
                                }).catch((err) => {
                                    console.log(err)
                                })
                            }).catch((err) => {
                                console.log(err)
                            })
                        }
                    }
                }
            }
        }
    })

    useEffect(() => {
        updateUserInfo()
    }, [])

    useEffect(() => {
        cacheUserAvatar()
    }, [userInfo])

    return (
        <Pressable style={{
            width: "100%",
            height: "auto",
            flexDirection: "row",
            justifyContent: "space-between",
            paddingLeft: 10,
            paddingRight: 10,
            paddingBottom: 10,
            paddingTop: 10,
            alignItems: "center"
        }} onPress={() => {
            if(!navigationEnabled){
                return false
            }

            if(!netInfo.isConnected || !netInfo.isInternetReachable){
                return showToast({ message: i18n(lang, "deviceOffline") })
            }

            navigationAnimation({ enable: true }).then(() => {
                navigation.dispatch(StackActions.push("SettingsAccountScreen"))
            })
        }}>
            <TouchableOpacity onPress={() => {
                if(Platform.OS == "android"){ // @TODO fix android avatar upload
                    return false
                }

                if(!netInfo.isConnected || !netInfo.isInternetReachable){
                    return showToast({ message: i18n(lang, "deviceOffline") })
                }
                
                SheetManager.show("ProfilePictureActionSheet")
            }}>
                <FastImage source={typeof userAvatarCached == "string" && userAvatarCached.length > 4 ? ({ uri: "file://" + MISC_BASE_PATH + userAvatarCached }) : (typeof userInfo !== "undefined" && userInfo.avatarURL.indexOf("https://down.") !== -1 ? { uri: userInfo.avatarURL } : require("../assets/images/appstore.png"))} style={{
                    width: 50,
                    height: 50,
                    borderRadius: 50
                }} />
            </TouchableOpacity>
            <View style={{
                width: "79%",
                paddingLeft: 15
            }}>
                <Text style={{
                    color: darkMode ? "white" : "black",
                    fontWeight: "bold",
                    fontSize: 19
                }} numberOfLines={1}>
                    {email}
                </Text>
                <Text style={{
                    color: "gray",
                    fontSize: 12,
                    marginTop: 1
                }} numberOfLines={1}>
                    {
                        typeof userInfo !== "undefined" ?
                            i18n(lang, "settingsHeaderUsage", true, ["__USAGE__", "__MAX__", "__PERCENT__"], [formatBytes(userInfo.storageUsed), formatBytes(userInfo.maxStorage), (isNaN((userInfo.storageUsed / userInfo.maxStorage * 100)) ? 0 : ((userInfo.storageUsed / userInfo.maxStorage * 100) >= 100) ? 100 : (userInfo.storageUsed / userInfo.maxStorage * 100).toFixed(2))])
                        :
                            i18n(lang, "settingsHeaderUsage", true, ["__USAGE__", "__MAX__", "__PERCENT__"], [formatBytes(0), formatBytes(0), 0])
                    }
                </Text>
            </View>
            <Ionicon name="chevron-forward-outline" size={22} color={navigationEnabled ? "gray" : "transparent"} />
        </Pressable>
    )
})
Example #21
Source File: Item.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
render(){
        const { item, index, darkMode } = this.props

        const calcedGridSize = calcPhotosGridSize(this.props.photosGridSize)
        const windowWidth = ((this.props.dimensions.window.width || window.width) - (this.props.insets.left + this.props.insets.right))
        const imageWidthAndHeight = Math.floor(windowWidth / calcedGridSize) - 1.5

        return (
            <Pressable key={index.toString()} style={{
                height: imageWidthAndHeight,
                width: imageWidthAndHeight,
                margin: 1,
                alignItems: "center",
                justifyContent: "center"
            }} onPress={() => {
                DeviceEventEmitter.emit("event", {
                    type: "item-onpress",
                    data: item
                })
            }} onLongPress={() => {
                DeviceEventEmitter.emit("event", {
                    type: "open-item-actionsheet",
                    data: item
                })
            }}>
                <FastImage source={this.props.hideThumbnails ? getImageForItem(item) : typeof item.thumbnail !== "undefined" ? { uri: "file://" + THUMBNAIL_BASE_PATH + item.thumbnail } : getImageForItem(item)} style={{
                    width: typeof item.thumbnail !== "undefined" && !this.props.hideThumbnails ? imageWidthAndHeight : 40,
                    height: typeof item.thumbnail !== "undefined" && !this.props.hideThumbnails ? imageWidthAndHeight : 40,
                    zIndex: 2
                }} onError={() => {
                    if(typeof item.thumbnail == "string"){
                        DeviceEventEmitter.emit("event", {
                            type: "check-thumbnail",
                            item
                        })
                    }
                }} />
                {
                    calcPhotosGridSize(this.props.photosGridSize) <= 5 && (
                        <>
                            {
                                item.favorited == 1 && (
                                    <Ionicon name="heart" size={19} color={"white"} style={{
                                        position: "absolute",
                                        bottom: 3,
                                        left: 3,
                                        zIndex: 100
                                    }} />
                                )
                            }
                            {
                                item.offline && (
                                    <>
                                        <Ionicon name="arrow-down-circle" size={18} color={"green"} style={{
                                            position: "absolute",
                                            top: 3,
                                            right: 2.8,
                                            zIndex: 100
                                        }} />
                                        <View style={{
                                            position: "absolute",
                                            top: 3,
                                            right: 3,
                                            width: 19,
                                            height: 19,
                                            borderRadius: 19,
                                            zIndex: 10,
                                            backgroundColor: "white"
                                        }}></View>
                                    </>
                                )
                            }
                            {
                                item.selected && (
                                    <>
                                        <Ionicon name="checkmark-circle" size={18} color="#0A84FF" style={{
                                            position: "absolute",
                                            bottom: 2.5,
                                            right: 2.8,
                                            zIndex: 100
                                        }} />
                                        <View style={{
                                            position: "absolute",
                                            bottom: 3,
                                            right: 3,
                                            width: 19,
                                            height: 19,
                                            borderRadius: 19,
                                            zIndex: 10,
                                            backgroundColor: "white"
                                        }}></View>
                                    </>
                                )
                            }
                        </>
                    )
                }
            </Pressable>
        )
    }
Example #22
Source File: Item.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
render(){
        const { item, index, darkMode } = this.props

        const windowWidth = ((this.props.dimensions.window.width || window.width) - (this.props.insets.left + this.props.insets.right))

        return (
            <Pressable key={index.toString()} style={{
                margin: 2,
                backgroundColor: darkMode ? (item.selected ? "#171717" : "black") : (item.selected ? "lightgray" : "white"),
                borderRadius: 5,
                height: Math.floor(windowWidth / 2) - 19 + 40,
                width: Math.floor(windowWidth / 2) - 19,
                borderColor: getColor(darkMode, "primaryBorder"),
                borderWidth: 1,
                marginTop: index <= 1 ? 10 : 0
            }} onPress={() => {
                DeviceEventEmitter.emit("event", {
                    type: "item-onpress",
                    data: item
                })
            }} onLongPress={() => {
                DeviceEventEmitter.emit("event", {
                    type: "item-onlongpress",
                    data: item
                })
            }}>
                <View style={{
                    width: "100%",
                    height: "100%"
                }}>
                    <View style={{
                        width: "100%",
                        height: Math.floor(windowWidth / 2) - 19,
                        alignItems: "center",
                        justifyContent: "center"
                    }}>
                        {
                            item.type == "folder" ? (
                                <Ionicon name="folder" size={40} color={getFolderColor(item.color)} />
                            ) : (
                                <>
                                    <FastImage source={this.props.hideThumbnails ? getImageForItem(item) : typeof item.thumbnail !== "undefined" ? { uri: "file://" + THUMBNAIL_BASE_PATH + item.thumbnail } : getImageForItem(item)} style={{
                                        width: item.type == "folder" ? 35 : typeof item.thumbnail !== "undefined" && !this.props.hideThumbnails ? "100%" : 35,
                                        height: item.type == "folder" ? 35 : typeof item.thumbnail !== "undefined" && !this.props.hideThumbnails ? "100%" : 35,
                                        borderTopLeftRadius: 4,
                                        borderTopRightRadius: 4
                                    }} onError={() => {
                                        if(typeof item.thumbnail == "string"){
                                            DeviceEventEmitter.emit("event", {
                                                type: "check-thumbnail",
                                                item
                                            })
                                        }
                                    }} />
                                    {
                                        item.favorited == 1 && (
                                            <Ionicon name="heart" size={19} color={"white"} style={{
                                                position: "absolute",
                                                bottom: 3,
                                                left: 3,
                                                zIndex: 100
                                            }} />
                                        )
                                    }
                                    {
                                        item.offline && (
                                            <>
                                                <Ionicon name="arrow-down-circle" size={18} color={"green"} style={{
                                                    position: "absolute",
                                                    top: 3,
                                                    right: 2.8,
                                                    zIndex: 100
                                                }} />
                                                <View style={{
                                                    position: "absolute",
                                                    top: 3,
                                                    right: 3,
                                                    width: 19,
                                                    height: 19,
                                                    borderRadius: 19,
                                                    zIndex: 10,
                                                    backgroundColor: "white"
                                                }}></View>
                                            </>
                                        )
                                    }
                                    {
                                        item.selected && (
                                            <>
                                                <Ionicon name="checkmark-circle" size={18} color="#0A84FF" style={{
                                                    position: "absolute",
                                                    bottom: 2.5,
                                                    right: 2.8,
                                                    zIndex: 100
                                                }} />
                                                <View style={{
                                                    position: "absolute",
                                                    bottom: 3,
                                                    right: 3,
                                                    width: 19,
                                                    height: 19,
                                                    borderRadius: 19,
                                                    zIndex: 10,
                                                    backgroundColor: "white"
                                                }}></View>
                                            </>
                                        )
                                    }
                                </>
                            )
                        }
                    </View>
                    <Pressable style={{
                        width: "100%",
                        height: "100%",
                        flexDirection: "row",
                        alignItems: "flex-start",
                        justifyContent: "space-between"
                    }} onPress={() => {
                        DeviceEventEmitter.emit("event", {
                            type: "open-item-actionsheet",
                            data: item
                        })
                    }}>
                        <View style={{
                            width: "80%",
                            paddingTop: 5,
                            paddingLeft: 8
                        }}>
                            <Text style={{
                                color: darkMode ? "white" : "black",
                                fontWeight: "bold",
                                fontSize: 11
                            }} numberOfLines={1}>{this.props.hideFileNames ? i18n(this.props.lang, item.type == "folder" ? "folder" : "file") : item.name}</Text>
                            <Text style={{
                                color: darkMode ? "white" : "black",
                                fontSize: 10,
                                paddingTop: 1
                            }} numberOfLines={1}>
                                {item.date}
                            </Text>
                        </View>
                        <TouchableOpacity style={{
                            paddingTop: 9,
                            paddingRight: 5
                        }} onPress={() => {
                            DeviceEventEmitter.emit("event", {
                                type: "open-item-actionsheet",
                                data: item
                            })
                        }}>
                            <Ionicon name="ellipsis-horizontal-sharp" size={18} color={darkMode ? "white" : "black"} />
                        </TouchableOpacity>
                    </Pressable>
                </View>
            </Pressable>
        )
    }
Example #23
Source File: InviteScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
InviteScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const [isLoading, setIsLoading] = useState(true)
    const [accountData, setAccountData] = useState({})
    const isMounted = useMountedState()

    useEffect(() => {
        getAccount().then((data) => {
            if(isMounted()){
                setAccountData(data)
                setIsLoading(false)
            }
        }).catch((err) => {
            console.log(err)

            showToast({ message: err.toString() })
        })
    }, [])

    return (
        <>
            <View style={{
                flexDirection: "row",
                justifyContent: "flex-start",
                backgroundColor: darkMode ? "black" : "white"
            }}>
                <TouchableOpacity style={{
                    marginTop: Platform.OS == "ios" ? 17 : 4,
                    marginLeft: 15,
                }} onPress={() => navigation.goBack()}>
                    <Ionicon name="chevron-back" size={24} color={darkMode ? "white" : "black"}></Ionicon>
                </TouchableOpacity>
                <Text style={{
                    color: darkMode ? "white" : "black",
                    fontWeight: "bold",
                    fontSize: 24,
                    marginLeft: 10,
                    marginTop: Platform.OS == "ios" ? 15 : 0
                }}>
                    {i18n(lang, "invite")}
                </Text>
            </View>
            <ScrollView style={{
                height: "100%",
                width: "100%",
                backgroundColor: darkMode ? "black" : "white"
            }}>
                {
                    isLoading ? (
                        <ActivityIndicator size={"small"} color={darkMode ? "white" : "black"} style={{
                            marginTop: "70%"
                        }} />
                    ) : (
                        <>
                            <SettingsGroup>
                                <View style={{
                                    width: "100%",
                                    height: "auto"
                                }}>
                                    <View style={{
                                        width: "100%",
                                        height: "auto",
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        paddingLeft: 10,
                                        paddingRight: 10,
                                        paddingTop: 10,
                                        paddingBottom: 10
                                    }}>
                                        <View>
                                            <Text style={{
                                                color: darkMode ? "white" : "black"
                                            }}>
                                                {i18n(lang, "inviteInfo")}
                                            </Text>
                                        </View>
                                    </View>
                                </View>
                            </SettingsGroup>
                            <SettingsGroup>
                                <View style={{
                                    width: "100%",
                                    height: "auto"
                                }}>
                                    <View style={{
                                        width: "100%",
                                        height: "auto",
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        paddingLeft: 10,
                                        paddingRight: 10,
                                        paddingTop: 10,
                                        paddingBottom: 10
                                    }}>
                                        <View>
                                            <Text style={{
                                                color: darkMode ? "white" : "black"
                                            }}>
                                                {i18n(lang, "inviteCount")}
                                            </Text>
                                        </View>
                                        <Text style={{
                                            color: darkMode ? "white" : "black"
                                        }}>
                                            {accountData.referCount > accountData.refLimit ? accountData.refLimit : accountData.referCount}/{accountData.refLimit}
                                        </Text>
                                    </View>
                                </View>
                            </SettingsGroup>
                            <SettingsGroup>
                                <Pressable style={{
                                    width: "100%",
                                    height: "auto"
                                }} onPress={() => {
                                    Clipboard.setString("https://filen.io/r/" + accountData.refId)

                                    showToast({ message: i18n(lang, "copiedToClipboard") })
                                }}>
                                    <View style={{
                                        width: "100%",
                                        height: "auto",
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        paddingLeft: 10,
                                        paddingRight: 10,
                                        paddingTop: 10,
                                        paddingBottom: 10
                                    }}>
                                        <Text style={{
                                            color: darkMode ? "white" : "black",
                                            width: "70%"
                                        }} numberOfLines={1}>
                                            https://filen.io/r/{accountData.refId}
                                        </Text>
                                        <TouchableOpacity onPress={() => {
                                            Share.share({
                                                message: i18n(lang, "shareRefLinkMessage"),
                                                url: "https://filen.io/r/" + accountData.refId
                                            })
                                        }}>
                                            <Text style={{
                                                color: "#0A84FF"
                                            }}>
                                                {i18n(lang, "share")}
                                            </Text>
                                       </TouchableOpacity>
                                        <TouchableOpacity onPress={() => {
                                            Clipboard.setString("https://filen.io/r/" + accountData.refId)

                                            showToast({ message: i18n(lang, "copiedToClipboard") })
                                        }}>
                                            <Text style={{
                                                color: "#0A84FF"
                                            }}>
                                                {i18n(lang, "copy")}
                                            </Text>
                                       </TouchableOpacity>
                                    </View>
                                </Pressable>
                            </SettingsGroup>
                            <View style={{
                                width: "100%",
                                height: "auto",
                                paddingLeft: 8,
                                paddingRight: 8,
                                marginTop: 5
                            }}>
                                <View style={{
                                    width: "100%",
                                    height: "auto",
                                    flexDirection: "row",
                                    justifyContent: "space-between",
                                    paddingLeft: 10,
                                    paddingRight: 10,
                                    paddingTop: 10,
                                    paddingBottom: 10
                                }}>
                                    <View>
                                        <Text style={{
                                            color: "gray",
                                            fontSize: 10
                                        }}>
                                            {i18n(lang, "inviteInfo2")}
                                        </Text>
                                    </View>
                                </View>
                            </View>
                        </>
                    )
                }
            </ScrollView>
        </>
    )
})
Example #24
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>
    )
})