react-use#useMountedState JavaScript Examples

The following examples show how to use react-use#useMountedState. 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: GDPRScreen.js    From filen-mobile with GNU Affero General Public License v3.0 5 votes vote down vote up
GDPRScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const [gdpr, setGdpr] = useState("")
    const [isLoading, setIsLoading] = useState(true)
    const isMounted = useMountedState()
    
    useEffect(() => {
        fetchGDPRInfo().then((info) => {
            if(isMounted()){
                setGdpr(JSON.stringify(info, null, 2))
                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, "showGDPR")}
                </Text>
            </View>
            <ScrollView style={{
                height: "100%",
                width: "100%",
                backgroundColor: darkMode ? "black" : "white"
            }}>
                {
                    isLoading ? (
                        <ActivityIndicator size={"small"} color={darkMode ? "white" : "black"} style={{
                            marginTop: "70%"
                        }} />
                    ) : (
                        <Text style={{
                            color: darkMode ? "white" : "black",
                            padding: 22
                        }}>
                            {striptags(gdpr)}    
                        </Text>
                    )
                }
            </ScrollView>
        </>
    )
})
Example #2
Source File: EventsScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
EventsInfoScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const [eventInfo, setEventInfo] = useState(undefined)
    const [isLoading, setIsLoading] = useState(true)
    const [eventText, setEventText] = useState("")
    const isMounted = useMountedState()

    const uuid = route?.params?.uuid

    useEffect(() => {
        setIsLoading(true)

        fetchEventInfo({ uuid }).then((info) => {
            if(isMounted()){
                setEventInfo(info)

                getEventText({ item: info, masterKeys: getMasterKeys(), lang }).then((text) => {
                    if(isMounted()){
                        setEventText(text)
                        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, "eventInfo")}
                </Text>
            </View>
            <ScrollView style={{
                height: "100%",
                width: "100%",
                backgroundColor: darkMode ? "black" : "white"
            }}>
                
                {
                    isLoading ? (
                        <ActivityIndicator size="small" color={darkMode ? "white" : "black"} style={{
                            marginTop: 100
                        }} />
                    ) : (
                        <>
                            <SettingsGroup>
                                <SettingsButton title={eventText} />
                            </SettingsGroup>
                            <SettingsGroup marginTop={10}>
                                <SettingsButton title={new Date(eventInfo.timestamp * 1000).toLocaleDateString() + " " + new Date(eventInfo.timestamp * 1000).toLocaleTimeString()} />
                            </SettingsGroup>
                            <SettingsGroup marginTop={10}>
                                <SettingsButton title={eventInfo.info.userAgent} />
                            </SettingsGroup>
                            <SettingsGroup marginTop={10}>
                                <SettingsButton title={eventInfo.info.ip} />
                            </SettingsGroup>
                        </>
                    )
                }
                <View style={{ height: 25 }}></View>
            </ScrollView>
        </>
    )
})
Example #3
Source File: EventsScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
EventsScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const [events, setEvents] = useState([])
    const [isLoading, setIsLoading] = useState(true)
    const [filter, setFilter] = useState("all")
    const [limit, setLimit] = useState(0)
    const [refreshing, setRefreshing] = useState(false)
    const dimensions = useStore(useCallback(state => state.dimensions))
    const [masterKeys, setMasterKeys] = useState(getMasterKeys())
    const isMounted = useMountedState()
    const [topHeight, setTopHeight] = useState(0)
    const bottomBarHeight = useStore(useCallback(state => state.bottomBarHeight))
    const contentHeight = useStore(useCallback(state => state.contentHeight))
    const onEndReachedCalledDuringMomentum = useRef(false)
    const lastEventId = useRef(0)

    const getEvents = useCallback((lastId) => {
        setIsLoading(true)
        
        fetchEvents({ lastId, filter }).then((data) => {
            if(isMounted()){
                setIsLoading(false)
                setRefreshing(false)

                const newEvents = data.events
                const limit = data.limit

                setEvents(prev => [...prev, ...newEvents])
                setLimit(limit)

                newEvents.map(event => console.log(event.id))
                
                lastEventId.current = newEvents[newEvents.length - 1].id
            }
        }).catch((err) => {
            console.log(err)

            showToast({ message: err.toString() })
        })
    })

    useEffect(() => {
        setEvents([])

        getEvents(lastEventId.current)
    }, [])

    return (
        <>
            <View style={{
                flexDirection: "row",
                justifyContent: "flex-start",
                backgroundColor: darkMode ? "black" : "white"
            }} onLayout={(e) => setTopHeight(e.nativeEvent.layout.height)}>
                <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, "events")}
                </Text>
            </View>
            <View style={{
                height: Math.floor(contentHeight - topHeight - bottomBarHeight + 31),
                width: "100%",
                backgroundColor: darkMode ? "black" : "white",
                paddingTop: 15
            }}>
                <FlatList
                    data={events}
                    keyExtractor={(item, index) => index}
                    key="events"
                    windowSize={10}
                    initialNumToRender={32}
                    removeClippedSubviews={true}
                    numColumns={1}
                    renderItem={({ item, index }) => <EventRow item={item} index={index} darkMode={darkMode} lang={lang} navigation={navigation} masterKeys={masterKeys} />}
                    onMomentumScrollBegin={() => onEndReachedCalledDuringMomentum.current = false}
                    onEndReachedThreshold={0.1}
                    onEndReached={() => {
                        if(limit <= events.length && limit > 0 && events.length > 0 && !onEndReachedCalledDuringMomentum.current){
                            onEndReachedCalledDuringMomentum.current = true

                            console.log("called")

                            getEvents(lastEventId.current)
                        }
                    }}
                    getItemLayout={(data, index) => (
                        {length: 45, offset: 45 * index, index}
                    )}
                    ListEmptyComponent={() => {
                        return (
                            <View style={{
                                width: "100%",
                                height: Math.floor(dimensions.screen.height - 255),
                                justifyContent: "center",
                                alignItems: "center",
                                alignContent: "center"
                            }}>
                                {
                                    isLoading ? (
                                        <View>
                                            <ActivityIndicator color={darkMode ? "white" : "black"} size="small" />
                                            <Text style={{
                                                color: darkMode ? "white" : "black",
                                                marginTop: 15
                                            }}>
                                                {i18n(lang, "loading")}
                                            </Text>
                                        </View>
                                    ) : (
                                        <ListEmpty route={route} searchTerm={""} />
                                    )
                                }
                            </View>
                        )
                    }}
                    refreshControl={
                        <RefreshControl
                            refreshing={refreshing}
                            onRefresh={() => {
                                if(!isLoading){
                                    return false
                                }
    
                                setRefreshing(true)
            
                                getEvents(0)
                            }}
                            tintColor={darkMode ? "white" : "black"}
                            size="default"
                        />
                    }
                    style={{
                        height: "100%",
                        width: "100%"
                    }}
                    ListFooterComponent={
                        isLoading ? (
                            <></>
                        ) : (
                            limit <= events.length && limit > 0 && events.length > 0 ? (
                                <View style={{
                                    height: 50,
                                    marginTop: 15
                                }}>
                                    <ActivityIndicator color={darkMode ? "white" : "black"} size="small" />
                                </View>
                            ) : (
                                <></>
                            )
                        )
                    }
                />
            </View>
        </>
    )
})
Example #4
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>
    )
})
Example #5
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 #6
Source File: MainScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
MainScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [userId, setUserId] = useMMKVNumber("userId", storage)
    const [routeURL, setRouteURL] = useState(useCallback(getRouteURL(route)))
    const cachedItemsRef = useRef(storage.getString("loadItemsCache:" + routeURL)).current
    const cachedItemsParsed = useRef(typeof cachedItemsRef == "string" ? JSON.parse(cachedItemsRef) : []).current
    const [items, setItems] = useState(Array.isArray(cachedItemsParsed) ? cachedItemsParsed.filter(item => item !== null && typeof item.uuid == "string") : [])
    const [searchTerm, setSearchTerm] = useState("")
    const [loadDone, setLoadDone] = useState(typeof cachedItemsRef !== "undefined" ? true : false)
    const setNavigation = useStore(useCallback(state => state.setNavigation))
    const setRoute = useStore(useCallback(state => state.setRoute))
    const [masterKeys, setMasterKeys] = useState(useCallback(getMasterKeys()))
    const isMounted = useMountedState()
    const setCurrentActionSheetItem = useStore(useCallback(state => state.setCurrentActionSheetItem))
    const setCurrentItems = useStore(useCallback(state => state.setCurrentItems))
    const itemsRef = useRef([])
    const setItemsSelectedCount = useStore(useCallback(state => state.setItemsSelectedCount))
    const setInsets = useStore(useCallback(state => state.setInsets))
    const insets = useSafeAreaInsets()
    const [progress, setProgress] = useState({ itemsDone: 0, totalItems: 1 })
    const selectedCountRef = useRef(0)
    const setIsDeviceReady = useStore(useCallback(state => state.setIsDeviceReady))
    const [itemsBeforeSearch, setItemsBeforeSearch] = useState([])
    const [photosGridSize, setPhotosGridSize] = useMMKVNumber("photosGridSize", storage)
    const bottomBarHeight = useStore(useCallback(state => state.bottomBarHeight))
    const topBarHeight = useStore(useCallback(state => state.topBarHeight))
    const contentHeight = useStore(useCallback(state => state.contentHeight))
    const [photosRange, setPhotosRange] = useMMKVString("photosRange:" + userId, storage)
    const netInfo = useStore(useCallback(state => state.netInfo))
    const itemsSortBy = useStore(useCallback(state => state.itemsSortBy))
    const [initialized, setInitialized] = useState(false)
    const isFocused = useIsFocused()

    const updateItemThumbnail = useCallback((item, path) => {
        if(typeof path !== "string"){
            return false
        }

        if(path.length < 4){
            return false
        }
    
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == item.uuid && typeof mapItem.thumbnail == "undefined" ? {...mapItem, thumbnail: item.uuid + ".jpg" } : mapItem))
        }
    })
    
    const selectItem = useCallback((item) => {
        if(getRouteURL(route).indexOf("photos") !== -1){
            if(calcPhotosGridSize(photosGridSize) >= 6){
                return false
            }
        }

        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == item.uuid ? {...mapItem, selected: true} : mapItem))
        }
    })
    
    const unselectItem = useCallback((item) => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == item.uuid ? {...mapItem, selected: false} : mapItem))
        }
    })

    const unselectAllItems = useCallback(() => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.selected ? {...mapItem, selected: false} : mapItem))
        }
    })

    const selectAllItems = useCallback(() => {
        if(getRouteURL(route).indexOf("photos") !== -1){
            if(calcPhotosGridSize(photosGridSize) >= 6){
                return false
            }
        }

        if(isMounted()){
            setItems(items => items.map(mapItem => !mapItem.selected ? {...mapItem, selected: true} : mapItem))
        }
    })

    const removeItem = useCallback((uuid) => {
        if(isMounted()){
            setItems(items => items.filter(mapItem => mapItem.uuid !== uuid && mapItem))
        }
    })

    const markOffline = useCallback((uuid, value) => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == uuid ? {...mapItem, offline: value} : mapItem))
        }
    })

    const markFavorite = useCallback((uuid, value) => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == uuid ? {...mapItem, favorited: value} : mapItem))
        }
    })

    const changeFolderColor = useCallback((uuid, color) => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == uuid && mapItem.type == "folder" ? {...mapItem, color} : mapItem))
        }
    })

    const changeItemName = useCallback((uuid, name) => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == uuid ? {...mapItem, name} : mapItem))
        }
    })

    const addItem = useCallback((item, parent) => {
        const currentParent = getParent(route)

        if(isMounted() && (currentParent == parent || (item.offline && parent == "offline"))){
            setItems(items => sortItems({ items: [...items, item], passedRoute: route }))
        }
    })

    const changeWholeItem = useCallback((item, uuid) => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == uuid ? item : mapItem))
        }
    })

    const reloadList = useCallback((parent) => {
        const currentParent = getParent(route)

        if(isMounted() && currentParent == parent){
            fetchItemList({ bypassCache: true, callStack: 1 })
        }
    })

    const updateFolderSize = useCallback((uuid, size) => {
        if(isMounted()){
            setItems(items => items.map(mapItem => mapItem.uuid == uuid && mapItem.type == "folder" ? {...mapItem, size} : mapItem))
        }
    })

    useEffect(() => {
        if(isMounted() && initialized){
            if(searchTerm.length == 0){
                if(itemsBeforeSearch.length > 0){
                    setItems(itemsBeforeSearch)
                    setItemsBeforeSearch([])
                }
            }
            else{
                if(itemsBeforeSearch.length == 0){
                    setItemsBeforeSearch(items)
    
                    var filtered = items.filter(item => item.name.toLowerCase().trim().indexOf(searchTerm.toLowerCase().trim()) !== -1 && item)
                }
                else{
                    var filtered = itemsBeforeSearch.filter(item => item.name.toLowerCase().trim().indexOf(searchTerm.toLowerCase().trim()) !== -1 && item)
                }
    
                setItems(filtered)
            }
        }
    }, [searchTerm])

    useEffect(() => {
        if(isMounted() && initialized){
            const sorted = sortItems({ items, passedRoute: route })

            setItems(sorted)
        }
    }, [itemsSortBy])

    useEffect(() => {
        if(isFocused){
            if(Array.isArray(items) && items.length > 0){
                setCurrentItems(items)

                itemsRef.current = items
                global.items = items

                const selected = items.filter(item => item.selected).length

                selectedCountRef.current = selected

                setItemsSelectedCount(selectedCountRef.current)
            }
            else{
                setCurrentItems([])
    
                itemsRef.current = []
                global.items = []
    
                setItemsSelectedCount(0)
            }

            global.setItems = setItems
        }
    }, [items, isFocused])

    const fetchItemList = useCallback(({ bypassCache = false, callStack = 0, loadFolderSizes = false }) => {
        return new Promise((resolve, reject) => {
            loadItems({
                parent: getParent(route),
                setItems,
                masterKeys,
                setLoadDone,
                navigation,
                isMounted,
                bypassCache,
                route,
                setProgress,
                callStack,
                loadFolderSizes
            }).then(resolve).catch(reject)
        })
    })

    useEffect(() => {
        setNavigation(navigation)
        setRoute(route)
        setInsets(insets)
        
        fetchItemList({ bypassCache: false, callStack: 0, loadFolderSizes: false }).catch((err) => console.log(err))

        global.fetchItemList = fetchItemList

        const deviceListener = DeviceEventEmitter.addListener("event", (data) => {
            const navigationRoutes = navigation.getState().routes
            const isListenerActive = typeof navigationRoutes == "object" ? (navigationRoutes[navigationRoutes.length - 1].key == route.key) : false

            if(data.type == "thumbnail-generated"){
                updateItemThumbnail(data.data, data.data.path)
            }
            else if(data.type == "item-onpress" && isListenerActive){
                if(data.data.selected){
                    unselectItem(data.data)
                }
                else{
                    if(selectedCountRef.current > 0){
                        selectItem(data.data)
                    }
                    else{
                        global.currentReceiverId = data.data.receiverId

                        try{
                            const currentRouteURL = getRouteURL(route)

                            if(typeof currentRouteURL == "string"){
                                if(data.data.type == "folder" && currentRouteURL.indexOf("trash") == -1){
                                    navigationAnimation({ enable: true }).then(() => {
                                        navigation.dispatch(StackActions.push("MainScreen", {
                                            parent: currentRouteURL + "/" + data.data.uuid
                                        }))
                                    })
                                }
                                else{
                                    previewItem({ item: data.data, navigation })
                                }
                            }
                            else{
                                console.log("route url !== string: ", currentRouteURL)
                            }
                        }
                        catch(e){
                            console.log(e)
                        }
                    }
                }
            }
            else if(data.type == "item-onlongpress" && isListenerActive){
                selectItem(data.data)
            }
            else if(data.type == "open-item-actionsheet" && isListenerActive){
                setCurrentActionSheetItem(data.data)
    
                SheetManager.show("ItemActionSheet")
            }
            else if(data.type == "unselect-all-items" && isListenerActive){
                unselectAllItems()
            }
            else if(data.type == "select-all-items" && isListenerActive){
                selectAllItems()
            }
            else if(data.type == "select-item" && isListenerActive){
                selectItem(data.data)
            }
            else if(data.type == "unselect-item" && isListenerActive){
                unselectItem(data.data)
            }
            else if(data.type == "remove-item"){
                removeItem(data.data.uuid)
            }
            else if(data.type == "add-item"){
                addItem(data.data.item, data.data.parent)
            }
            else if(data.type == "mark-item-offline"){
                if(!data.data.value && getRouteURL(route).indexOf("offline") !== -1){
                    removeItem(data.data.uuid)
                }
                else{
                    markOffline(data.data.uuid, data.data.value)
                }
            }
            else if(data.type == "mark-item-favorite"){
                if(!data.data.value && getRouteURL(route).indexOf("favorites") !== -1){
                    removeItem(data.data.uuid)
                }
                else{
                    markFavorite(data.data.uuid, data.data.value)
                }
            }
            else if(data.type == "change-folder-color"){
                changeFolderColor(data.data.uuid, data.data.color)
            }
            else if(data.type == "change-item-name"){
                changeItemName(data.data.uuid, data.data.name)
            }
            else if(data.type == "change-whole-item"){
                changeWholeItem(data.data.item, data.data.uuid)
            }
            else if(data.type == "reload-list"){
                reloadList(data.data.parent)
            }
            else if(data.type == "remove-public-link"){
                if(getRouteURL(route).indexOf("links") !== -1){
                    removeItem(data.data.uuid)
                }
            }
            else if(data.type == "folder-size"){
                updateFolderSize(data.data.uuid, data.data.size)
            }
        })

        setIsDeviceReady(true)
        setInitialized(true)

        return () => {
            deviceListener.remove()
            
            setPhotosRange("all")
        }
    }, [])

    return (
        <View style={{
            height: "100%",
            width: "100%",
            backgroundColor: darkMode ? "black" : "white"
        }}>
            <TopBar navigation={navigation} route={route} setLoadDone={setLoadDone} searchTerm={searchTerm} setSearchTerm={setSearchTerm} />
            <View style={{
                height: routeURL.indexOf("photos") !== -1 ? (contentHeight - 40 - bottomBarHeight + (Platform.OS == "android" ? 35 : 26)) : (contentHeight - topBarHeight - bottomBarHeight + 30)
            }}>
                <ItemList navigation={navigation} route={route} items={items} setItems={setItems} showLoader={!loadDone} loadDone={loadDone} searchTerm={searchTerm} isMounted={isMounted} fetchItemList={fetchItemList} progress={progress} setProgress={setProgress} />
            </View>
        </View>
    )
})
Example #7
Source File: SettingsAccountScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
SettingsAccountScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const setRedeemCodeDialogVisible = useStore(useCallback(state => state.setRedeemCodeDialogVisible))
    const setDeleteAccountTwoFactorDialogVisible = useStore(useCallback(state => state.setDeleteAccountTwoFactorDialogVisible))
    const [accountSettings, setAccountSettings] = useState({})
    const [isLoading, setIsLoading] = useState(true)
    const isMounted = useMountedState()

    useEffect(() => {
        getSettings().then((settings) => {
            if(isMounted()){
                setAccountSettings(settings)
                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, "accountSettings")}
                </Text>
            </View>
            <ScrollView style={{
                height: "100%",
                width: "100%",
                backgroundColor: darkMode ? "black" : "white"
            }}>
                {
                    isLoading ? (
                        <ActivityIndicator size={"small"} color={darkMode ? "white" : "black"} style={{
                            marginTop: "70%"
                        }} />
                    ) : (
                        <>
                            <SettingsGroup marginTop={15}>
                                <SettingsButtonLinkHighlight onPress={() => {
                                    navigationAnimation({ enable: true }).then(() => {
                                        navigation.dispatch(StackActions.push("ChangeEmailPasswordScreen"))
                                    })
                                }} title={i18n(lang, "changeEmailPassword")} />
                                <SettingsButtonLinkHighlight onPress={() => {
                                    navigationAnimation({ enable: true }).then(() => {
                                        navigation.dispatch(StackActions.push("TwoFactorScreen", {
                                            accountSettings
                                        }))
                                    })
                                }} title={i18n(lang, accountSettings.twoFactorEnabled ? "disable2FA" : "enable2FA")} />
                                <SettingsButtonLinkHighlight onPress={() => {
                                    navigationAnimation({ enable: true }).then(() => {
                                        navigation.dispatch(StackActions.push("GDPRScreen"))
                                    })
                                }} title={i18n(lang, "showGDPR")} />
                            </SettingsGroup>
                            <SettingsGroup>
                                <SettingsButtonLinkHighlight rightText={formatBytes(accountSettings.storageUsed)} onPress={() => {
                                    Alert.alert(i18n(lang, "deleteAllFiles"), i18n(lang, "deleteAllFilesInfo"), [
                                        {
                                            text: i18n(lang, "cancel"),
                                            onPress: () => {
                                                return false
                                            },
                                            style: "cancel"
                                        },
                                        {
                                            text: i18n(lang, "ok"),
                                            onPress: () => {
                                                Alert.alert(i18n(lang, "deleteAllFiles"), i18n(lang, "areYouReallySure"), [
                                                    {
                                                        text: i18n(lang, "cancel"),
                                                        onPress: () => {
                                                            return false
                                                        },
                                                        style: "cancel"
                                                    },
                                                    {
                                                        text: i18n(lang, "ok"),
                                                        onPress: () => {
                                                            useStore.setState({ fullscreenLoadingModalVisible: true })

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

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

                                                                setAccountSettings(prev => ({ ...prev, storageUsed: 0  }))
                                                            }).catch((err) => {
                                                                console.log(err)

                                                                useStore.setState({ fullscreenLoadingModalVisible: false })

                                                                showToast({ message: err.toString() })
                                                            })
                                                        },
                                                        style: "default"
                                                    }
                                                ], {
                                                    cancelable: true
                                                })
                                            },
                                            style: "default"
                                        }
                                    ], {
                                        cancelable: true
                                    })
                                }} title={i18n(lang, "deleteAllFiles")} />
                                <SettingsButtonLinkHighlight rightText={formatBytes(accountSettings.versionedStorage)} onPress={() => {
                                    Alert.alert(i18n(lang, "deleteAllVersionedFiles"), i18n(lang, "deleteAllVersionedFilesInfo"), [
                                        {
                                            text: i18n(lang, "cancel"),
                                            onPress: () => {
                                                return false
                                            },
                                            style: "cancel"
                                        },
                                        {
                                            text: i18n(lang, "ok"),
                                            onPress: () => {
                                                Alert.alert(i18n(lang, "deleteAllVersionedFiles"), i18n(lang, "areYouReallySure"), [
                                                    {
                                                        text: i18n(lang, "cancel"),
                                                        onPress: () => {
                                                            return false
                                                        },
                                                        style: "cancel"
                                                    },
                                                    {
                                                        text: i18n(lang, "ok"),
                                                        onPress: () => {
                                                            useStore.setState({ fullscreenLoadingModalVisible: true })

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

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

                                                                setAccountSettings(prev => ({ ...prev, storageUsed: (prev.storageUsed - prev.versionedStorage) }))
                                                                setAccountSettings(prev => ({ ...prev, versionedStorage: 0  }))
                                                            }).catch((err) => {
                                                                console.log(err)

                                                                useStore.setState({ fullscreenLoadingModalVisible: false })

                                                                showToast({ message: err.toString() })
                                                            })
                                                        },
                                                        style: "default"
                                                    }
                                                ], {
                                                    cancelable: true
                                                })
                                            },
                                            style: "default"
                                        }
                                    ], {
                                        cancelable: true
                                    })
                                }} title={i18n(lang, "deleteAllVersionedFiles")} />
                            </SettingsGroup>
                            <SettingsGroup>
                                <SettingsButtonLinkHighlight onPress={() => setRedeemCodeDialogVisible(true)} title={i18n(lang, "redeemACode")} />
                                <SettingsButtonLinkHighlight onPress={() => {
                                    navigationAnimation({ enable: true }).then(() => {
                                        navigation.dispatch(StackActions.push("InviteScreen"))
                                    })
                                }} title={i18n(lang, "invite")} />
                            </SettingsGroup>
                            <SettingsGroup>
                                <SettingsButtonLinkHighlight onPress={() => {
                                    Alert.alert(i18n(lang, "logout"), i18n(lang, "areYouReallySure"), [
                                        {
                                            text: i18n(lang, "cancel"),
                                            onPress: () => {
                                                return false
                                            },
                                            style: "cancel"
                                        },
                                        {
                                            text: i18n(lang, "ok"),
                                            onPress: () => logout({ navigation }),
                                            style: "default"
                                        }
                                    ], {
                                        cancelable: true
                                    })
                                }} title={i18n(lang, "logout")} />
                            </SettingsGroup>
                            <SettingsGroup>
                                <SettingsButtonLinkHighlight onPress={() => {
                                    Alert.alert(i18n(lang, "deleteAccount"), i18n(lang, "deleteAccountInfo"), [
                                        {
                                            text: i18n(lang, "cancel"),
                                            onPress: () => {
                                                return false
                                            },
                                            style: "cancel"
                                        },
                                        {
                                            text: i18n(lang, "ok"),
                                            onPress: () => {
                                                Alert.alert(i18n(lang, "deleteAccount"), i18n(lang, "areYouReallySure"), [
                                                    {
                                                        text: i18n(lang, "cancel"),
                                                        onPress: () => {
                                                            return false
                                                        },
                                                        style: "cancel"
                                                    },
                                                    {
                                                        text: i18n(lang, "ok"),
                                                        onPress: () => {
                                                            useStore.setState({ fullscreenLoadingModalVisible: true })

                                                            getSettings().then((settings) => {
                                                                if(settings.twoFactorEnabled){
                                                                    useStore.setState({ fullscreenLoadingModalVisible: false })

                                                                    return setDeleteAccountTwoFactorDialogVisible(true)
                                                                }

                                                                deleteAccount({ twoFactorKey: "XXXXXX" }).then(() => {
                                                                    useStore.setState({ fullscreenLoadingModalVisible: false })

                                                                    logout({ navigation })
                                                                }).catch((err) => {
                                                                    console.log(err)

                                                                    useStore.setState({ fullscreenLoadingModalVisible: false })

                                                                    showToast({ message: err.toString() })
                                                                })
                                                            }).catch((err) => {
                                                                console.log(err)

                                                                useStore.setState({ fullscreenLoadingModalVisible: false })

                                                                showToast({ message: err.toString() })
                                                            })
                                                        },
                                                        style: "default"
                                                    }
                                                ], {
                                                    cancelable: true
                                                })
                                            },
                                            style: "default"
                                        }
                                    ], {
                                        cancelable: true
                                    })
                                }} title={i18n(lang, "deleteAccount")} />
                            </SettingsGroup>
                            <View style={{ height: 25 }}></View>
                        </>
                    )
                }
            </ScrollView>
        </>
    )
})
Example #8
Source File: TransfersScreen.js    From filen-mobile with GNU Affero General Public License v3.0 4 votes vote down vote up
TransfersScreen = memo(({ navigation, route }) => {
    const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
    const [lang, setLang] = useMMKVString("lang", storage)
    const [sortedTransfers, setSortedTransfers] = useState([])
    const isMounted = useMountedState()
    const [currentView, setCurrentView] = useState("ongoing")
    const [ongoingTransfers, setOngoingTransfers] = useState(0)
    const [finishedTransfers, setFinishedTransfers] = useState(0)
    const [ongoingTransfersList, setOngoingTransfersList] = useState([])
    const [finishedTransfersList, setFinishedTransfersList] = useState([])
    const bottomBarHeight = useStore(useCallback(state => state.bottomBarHeight))
    const contentHeight = useStore(useCallback(state => state.contentHeight))
    const [topBarHeight, setTopBarHeight] = useState(useStore.getState().topBarHeight)

    const updateTransfers = useCallback(() => {
        if(isMounted()){
            const transfers = memoryCache.get("transfers") || {}
            
            for(let prop in transfers){
                if(prop.indexOf("upload") !== -1){
                    if(typeof transfers['upload:' + transfers[prop].id] == "undefined"){
                        transfers['upload:' + transfers[prop].id] = transfers[prop]
                    }
                }
                else{
                    if(typeof transfers['download:' + transfers[prop].id] == "undefined"){
                        transfers['download:' + transfers[prop].id] = transfers[prop]
                    }
                }
            }

            const sortedTransfers = []
            let finished = 0
            let ongoing = 0

            for(let prop in transfers){
                const transferDone = transfers[prop].chunksDone >= transfers[prop].file.chunks ? 1 : 0

                sortedTransfers.push({
                    id: prop,
                    type: prop.indexOf("upload") !== -1 ? "upload" : "download",
                    done: transferDone,
                    transfer: transfers[prop]
                })

                if(transferDone){
                    finished += 1
                }
                else{
                    ongoing += 1
                }
            }

            setOngoingTransfers(ongoing)
            setFinishedTransfers(finished)

            const finishedList = []
            const ongoingList = []

            if(sortedTransfers.length > 0){
                //const sorted = sortedTransfers.sort((a, b) => {
                //    return a.done > b.done
                //})

                const sorted = sortedTransfers.sort((a, b) => {
                    return (isNaN(Math.round((a.transfer.chunksDone / a.transfer.file.chunks) * 100)) ? 0 : Math.round((a.transfer.chunksDone / a.transfer.file.chunks) * 100)) < (isNaN(Math.round((b.transfer.chunksDone / b.transfer.file.chunks) * 100)) ? 0 : Math.round((b.transfer.chunksDone / b.transfer.file.chunks) * 100))
                })
    
                setSortedTransfers(sorted)

                for(let i = 0; i < sorted.length; i++){
                    if(sorted[i].done){
                        finishedList.push(sorted[i])
                    }
                    else{
                        ongoingList.push(sorted[i])
                    }
                }
            }

            setFinishedTransfersList(finishedList)
            setOngoingTransfersList(ongoingList)

            BackgroundTimer.setTimeout(updateTransfers, 100)
        }
    })

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

    return (
        <View style={{
            height: "100%",
            width: "100%",
            backgroundColor: darkMode ? "black" : "white"
        }}>
            <View style={{
                width: "100%",
                height: Platform.OS == "android" ? 75 : 87
            }} onLayout={(e) => setTopBarHeight(e.nativeEvent.layout.height)}>
                <View style={{
                    flexDirection: "row",
                    justifyContent: "space-between",
                    backgroundColor: darkMode ? "black" : "white"
                }}>
                    <View style={{
                        flexDirection: "row"
                    }}>
                        <TouchableOpacity style={{
                            marginTop: Platform.OS == "ios" ? 16 : 3,
                            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: 22,
                            marginLeft: 10,
                            marginTop: Platform.OS == "ios" ? 15 : 0
                        }}>
                            {i18n(lang, "transfers")}
                        </Text>
                    </View>
                    <TouchableOpacity hitSlop={{
                        top: 10,
                        right: 10,
                        left: 10,
                        bottom: 10
                    }} style={{
                        alignItems: "flex-end",
                        flexDirection: "row",
                        backgroundColor: "transparent",
                        height: "100%",
                        paddingLeft: 0,
                        paddingRight: 15
                    }} onPress={() => SheetManager.show("TopBarActionSheet")}>
                        {
                            ongoingTransfers > 0 && (
                                <View>
                                    <Ionicon name="ellipsis-horizontal-sharp" size={24} color={darkMode ? "white" : "black"}></Ionicon>
                                </View>
                            )
                        }
                    </TouchableOpacity>
                </View>
                <View style={{
                    height: "auto",
                    width: "100%",
                    flexDirection: "row",
                    justifyContent: "space-between",
                    marginTop: 20
                }}>
                    <TouchableOpacity style={{
                        borderBottomWidth: currentView == "ongoing" ? Platform.OS == "ios" ? 1.5 : 2 : 1,
                        borderBottomColor: currentView == "ongoing" ? "#0A84FF" : getColor(darkMode, "primaryBorder"),
                        height: 27,
                        paddingLeft: 15,
                        paddingRight: 15,
                        width: "50%",
                        alignItems: "center"
                    }} hitSlop={{
                        top: 20
                    }} onPress={() => setCurrentView("ongoing")}>
                        <Text style={{
                            color: currentView == "ongoing" ? "#0A84FF" : "gray",
                            fontWeight: "bold",
                            fontSize: 14
                        }}>
                            {i18n(lang, "ongoing")}
                        </Text>
                    </TouchableOpacity>
                    <TouchableOpacity style={{
                        borderBottomWidth: currentView == "finished" ? Platform.OS == "ios" ? 1.5 : 2 : 1,
                        borderBottomColor: currentView == "finished" ? "#0A84FF" : getColor(darkMode, "primaryBorder"),
                        height: 27,
                        paddingLeft: 15,
                        paddingRight: 15,
                        width: "50%",
                        alignItems: "center"
                    }} hitSlop={{
                        top: 20
                    }} onPress={() => setCurrentView("finished")}>
                        <Text style={{
                            color: currentView == "finished" ? "#0A84FF" : "gray",
                            fontWeight: "bold",
                            fontSize: 14
                        }}>
                            {i18n(lang, "finished")}
                        </Text>
                    </TouchableOpacity>
                </View>
            </View>
            <View style={{
                width: "100%",
                height: (contentHeight - topBarHeight - bottomBarHeight + 30)
            }}>
                {
                    currentView == "ongoing" && (
                        <FlatList
                            data={ongoingTransfersList}
                            keyExtractor={(item, index) => index}
                            key="ongoing"
                            windowSize={10}
                            initialNumToRender={32}
                            removeClippedSubviews={true}
                            numColumns={1}
                            renderItem={({ item, index }) => {
                                const transfer = item
                                
                                return (
                                    <View key={index} style={{
                                        width: "100%",
                                        height: 40,
                                        paddingTop: 10,
                                        paddingBottom: 10,
                                        paddingLeft: 15,
                                        paddingRight: 15,
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        alignItems: "center",
                                        borderBottomColor: getColor(darkMode, "primaryBorder"),
                                        borderBottomWidth: 1
                                    }}>
                                        <View style={{
                                            flexDirection: "row",
                                            width: "50%"
                                        }}>
                                            <Ionicon name={transfer.transfer.paused ? "pause-circle-outline" : transfer.type == "upload" ? "arrow-up-outline" : "arrow-down-outline"} size={20} color={darkMode ? "white" : "black"} />
                                            <Text style={{
                                                color: darkMode ? "white" : "black",
                                                marginLeft: 10,
                                                paddingTop: 2
                                            }} numberOfLines={1}>
                                                {transfer.transfer.file.name}
                                            </Text>
                                        </View>
                                        <View style={{
                                            marginLeft: 20
                                        }}>
                                            <Text style={{
                                                color: darkMode ? "white" : "black"
                                            }}>
                                                {
                                                    transfer.transfer.chunksDone == 0 ? (
                                                        <>{i18n(lang, "queued")}</>
                                                    ) : (
                                                        <>{!isNaN(Math.round((transfer.transfer.chunksDone / transfer.transfer.file.chunks) * 100)) ? (Math.round((transfer.transfer.chunksDone / transfer.transfer.file.chunks) * 100) >= 100 ? 100 : Math.round((transfer.transfer.chunksDone / transfer.transfer.file.chunks) * 100)) : 0}%</>
                                                    )
                                                }
                                            </Text>
                                        </View>
                                        {
                                            transfer.transfer.paused ? (
                                                <TouchableOpacity onPress={() => {
                                                    if(transfer.type == "upload"){
                                                        const currentUploads = useStore.getState().uploads
                                                        let didChange = false

                                                        for(let prop in currentUploads){
                                                            if(transfer.transfer.id == currentUploads[prop].id){
                                                                currentUploads[prop].paused = false
                                                                didChange = true
                                                            }
                                                        }

                                                        if(didChange){
                                                            useStore.setState({
                                                                uploads: currentUploads
                                                            })
                                                        }
                                                    }
                                                    else{
                                                        const currentDownloads = useStore.getState().downloads
                                                        let didChange = false
    
                                                        for(let prop in currentDownloads){
                                                            if(transfer.transfer.id == currentDownloads[prop].id){
                                                                currentDownloads[prop].paused = false
                                                                didChange = true
                                                            }
                                                        }

                                                        if(didChange){
                                                            useStore.setState({
                                                                downloads: currentDownloads
                                                            })
                                                        }
                                                    }
                                                }}>
                                                    <Text style={{
                                                        color: "#0A84FF"
                                                    }}>
                                                        {i18n(lang, "resume")}
                                                    </Text>
                                                </TouchableOpacity>
                                            ) : (
                                                <TouchableOpacity onPress={() => {
                                                    if(transfer.type == "upload"){
                                                        const currentUploads = useStore.getState().uploads
                                                        let didChange = false
    
                                                        for(let prop in currentUploads){
                                                            if(transfer.transfer.id == currentUploads[prop].id){
                                                                currentUploads[prop].paused = true
                                                                didChange = true
                                                            }
                                                        }

                                                        if(didChange){
                                                            useStore.setState({
                                                                uploads: currentUploads
                                                            })
                                                        }
                                                    }
                                                    else{
                                                        const currentDownloads = useStore.getState().downloads
                                                        let didChange = false
    
                                                        for(let prop in currentDownloads){
                                                            if(transfer.transfer.id == currentDownloads[prop].id){
                                                                currentDownloads[prop].paused = true
                                                                didChange = true
                                                            }
                                                        }

                                                        if(didChange){
                                                            useStore.setState({
                                                                downloads: currentDownloads
                                                            })
                                                        }
                                                    }
                                                }}>
                                                    <Text style={{
                                                        color: "#0A84FF"
                                                    }}>
                                                        {i18n(lang, "pause")}
                                                    </Text>
                                                </TouchableOpacity>
                                            )
                                        }
                                        <TouchableOpacity onPress={() => {
                                            if(transfer.type == "upload"){
                                                const currentUploads = useStore.getState().uploads
                                                let didChange = false

                                                for(let prop in currentUploads){
                                                    if(transfer.transfer.id == currentUploads[prop].id){
                                                        currentUploads[prop].stopped = true
                                                        didChange = true
                                                    }
                                                }

                                                if(didChange){
                                                    useStore.setState({
                                                        uploads: currentUploads
                                                    })
                                                }
                                            }
                                            else{
                                                const currentDownloads = useStore.getState().downloads
                                                let didChange = false

                                                for(let prop in currentDownloads){
                                                    if(transfer.transfer.id == currentDownloads[prop].id){
                                                        currentDownloads[prop].stopped = true
                                                        didChange = true
                                                    }
                                                }

                                                if(didChange){
                                                    useStore.setState({
                                                        downloads: currentDownloads
                                                    })
                                                }
                                            }
                                        }}>
                                            <Text style={{
                                                color: "#0A84FF"
                                            }}>
                                                {i18n(lang, "stop")}
                                            </Text>
                                        </TouchableOpacity>
                                    </View>
                                )
                            }}
                            getItemLayout={(data, index) => (
                                {length: 40, offset: 40 * index, index}
                            )}
                            style={{
                                height: "100%",
                                width: "100%"
                            }}
                            ListEmptyComponent={() => {
                                return (
                                    <View style={{
                                        marginTop: "60%",
                                        justifyContent: "center",
                                        alignItems: "center"
                                    }}>
                                        <Ionicon name="repeat-outline" size={70} color="gray" />
                                        <Text style={{
                                            color: "gray",
                                            marginTop: 5
                                        }}>
                                            {i18n(lang, "noTransfers")}
                                        </Text>
                                    </View>
                                )
                            }}
                        />
                    )
                }
                {
                    currentView == "finished" && (
                        <FlatList
                            data={finishedTransfersList}
                            keyExtractor={(item, index) => index}
                            key="ongoing"
                            windowSize={10}
                            initialNumToRender={32}
                            removeClippedSubviews={true}
                            numColumns={1}
                            renderItem={({ item, index }) => {
                                const transfer = item
                                
                                return (
                                    <View key={index} style={{
                                        width: "100%",
                                        height: 40,
                                        paddingTop: 10,
                                        paddingBottom: 10,
                                        paddingLeft: 15,
                                        paddingRight: 15,
                                        flexDirection: "row",
                                        justifyContent: "space-between",
                                        alignItems: "center",
                                        borderBottomColor: getColor(darkMode, "primaryBorder"),
                                        borderBottomWidth: 1
                                    }}>
                                        <View style={{
                                            flexDirection: "row",
                                            width: "90%"
                                        }}>
                                            <Ionicon name={transfer.type == "upload" ? "arrow-up-outline" : "arrow-down-outline"} size={20} color={darkMode ? "white" : "black"} />
                                            <Text style={{
                                                color: darkMode ? "white" : "black",
                                                marginLeft: 10,
                                                paddingTop: 2
                                            }} numberOfLines={1}>
                                                {transfer.transfer.file.name}
                                            </Text>
                                        </View>
                                    </View>
                                )
                            }}
                            getItemLayout={(data, index) => (
                                {length: 40, offset: 40 * index, index}
                            )}
                            style={{
                                height: "100%",
                                width: "100%"
                            }}
                            ListEmptyComponent={() => {
                                return (
                                    <View style={{
                                        marginTop: "60%",
                                        justifyContent: "center",
                                        alignItems: "center"
                                    }}>
                                        <Ionicon name="repeat-outline" size={70} color="gray" />
                                        <Text style={{
                                            color: "gray",
                                            marginTop: 5
                                        }}>
                                            {i18n(lang, "noFinishedTransfers")}
                                        </Text>
                                    </View>
                                )
                            }}
                        />
                    )
                }
            </View>
        </View>
    )
})