Sunday, 23 February 2020

Expo image editor 3 share

long press on image in grid view

enter editor, press blue round button bottom right

fig opens, press green share button

share dialog opens, press gmail

image is added to attachment
//editor.js

import React, { useState, useEffect } from 'react';
import { BackHandler } from 'react-native';
import * as MediaLibrary from 'expo-media-library';
import * as Sharing from 'expo-sharing';
import * as FileSystem from 'expo-file-system';
import { Image, ImageBackground, Alert, Dimensions, ScrollView } from 'react-native'
import {
    Container, Header, Title, Content, Footer,
    FooterTab, Button, Left, Right, Body, Icon, Text,
    Accordion, Card, CardItem, Thumbnail, ListItem,
    CheckBox, DatePicker, DeckSwiper, Fab, View,
    Badge, Form, Item, Input, Label, Picker, Textarea,
    Switch, Radio, Spinner, Tab, Tabs, TabHeading,
    ScrollableTab, H1, H2, H3, Drawer, Toast
} from 'native-base';
import {
    Ionicons, MaterialIcons, Foundation,
    MaterialCommunityIcons, Octicons
} from '@expo/vector-icons';
import ReactNativeZoomableView from '@dudigital/react-native-zoomable-view/src/ReactNativeZoomableView';
import { Col, Row, Grid } from "react-native-easy-grid";

const picWidth = Math.round(Dimensions.get('window').width) / 2 - 20;

export default function Editor(props) {
    const [gallaryPic, setgalleryPic] = useState([])
    const [currentPic, setcurrentPic] = useState(0)
    const [openGridView, setopenGridView] = useState(false)
    const [selectedPic, setselectedPic] = useState([])
    const [activeFab, setactiveFab] = useState(false)

    useEffect(() => {
        setcurrentPic(0)
        getPictureFromGallary()

        //if back key is pressed on the phone, close editor
        BackHandler.addEventListener('hardwareBackPress', () => {
            props.closeEditor()
        });

        //component will unmount
        return () => { BackHandler.removeEventListener('hardwareBackPress') }
    }, [])

    getPictureFromGallary = async () => {
        const pics = await MediaLibrary.getAssetsAsync({
            sortBy: MediaLibrary.SortBy.creationTime
        })

        //await setdefaultPicture(pics.assets[0].uri)
        await setgalleryPic(pics.assets)
    }

    previousPic = () => {
        const length = gallaryPic.length
        if (length === 0) { return }

        currentPic > 0 ? setcurrentPic(currentPic - 1) : setcurrentPic(length - 1)
    }

    nextPic = () => {
        const length = gallaryPic.length
        if (length === 0) { return }

        currentPic < length - 1 ? setcurrentPic(currentPic + 1) : setcurrentPic(0)
    }

    confirmDelete = async () => {
        //remove picture in android directory
        await MediaLibrary.deleteAssetsAsync(gallaryPic[currentPic])
        //remove picture in memory
        setgalleryPic(gallaryPic.filter(item => { return item !== gallaryPic[currentPic] }))
        //correct current pic index
        previousPic()
        nextPic()
    }

    togglePicHighlight = (id) => {
        selectedPic.includes(id) ?
            setselectedPic(selectedPic.filter(_id => { return _id !== id })) :
            setselectedPic(selectedPic.concat(id))
    }

    picLongPress = (index) => {
        setcurrentPic(index)
        setopenGridView(false)
    }

    deletePics = () => {
        selectedPic.forEach(async (id) => {
            removePic = gallaryPic.find(item => item.id === id)
            //remove picture in android directory
            await MediaLibrary.deleteAssetsAsync(removePic)
        })

        //remove picture in memory
        setgalleryPic(gallaryPic.filter(item => !selectedPic.includes(item.id)))

        setselectedPic([])
        setcurrentPic(0)
    }

    shareImage = async (image) => {
        //copy image from memory to app cache, app cache will be automatically cleaned when storage is low
        //sharing can't access 'file:///storage/emulated/0/DCIM/e3bda948-2407-47e1-b5cf-12e7705bf86e.jpg'
        //have to copy to 'file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540chuanshuoge%252Fexpo-medialibrary/e3bda948-2407-47e1-b5cf-12e7705bf86e.jpg'
        //console.log(FileSystem.cacheDirectory + image.filename)
        await FileSystem.copyAsync({
            from: image.uri,
            to: FileSystem.cacheDirectory + image.filename
        })

        await Sharing.shareAsync(FileSystem.cacheDirectory + image.filename)
    }

    return (
        <Container>
            <Header style={{ marginTop: 25 }}>
                <Left>
                    <Button transparent onPress={() => props.closeEditor()}>
                        <Ionicons name='ios-arrow-round-back' size={40} color="white"></Ionicons>
                    </Button>
                </Left>
                <Body style={{ alignItems: 'center' }}>
                    <Title>Editor</Title>
                </Body>
                <Right>
                    <Button transparent iconRight onPress={() => setopenGridView(true)}>
                        <Text style={{ color: 'white' }}>Gallary{' '}</Text>
                        <Ionicons name='ios-arrow-round-forward' size={40} color="white"></Ionicons>
                    </Button>
                </Right>
            </Header>
            <View style={{ flex: 1 }}>
                {gallaryPic.length > 0 ?
                    <ImageBackground source={require('./assets/background.jpg')}
                        style={{ flex: 1, resizeMode: 'stretch' }}>
                        <ReactNativeZoomableView
                            maxZoom={1.5}
                            minZoom={0.5}
                            zoomStep={0.5}
                            initialZoom={1}
                            bindToBorders={true}>

                            <Image style={{ width: '100%', height: '100%', resizeMode: 'contain' }}
                                source={{ uri: gallaryPic[currentPic].uri }} />

                        </ReactNativeZoomableView>
                    </ImageBackground>
                    : null}

                {openGridView ? null :
                    <Fab
                        active={activeFab}
                        direction="up"
                        containerStyle={{}}
                        style={{ backgroundColor: '#5067FF' }}
                        position="bottomRight"
                        onPress={() => activeFab ? setactiveFab(false) : setactiveFab(true)}>
                        <Foundation name='social-yelp'></Foundation>

                        <Button style={{ backgroundColor: '#34A34F' }}
                            onPress={() => shareImage(gallaryPic[currentPic])}>
                            <Foundation name='share' size={30} color="white"></Foundation>
                        </Button>
                        <Button style={{ backgroundColor: '#3B5998' }}
                            onPress={() => alert('double tap on image to zoom')}>
                            <Foundation name='zoom-in' size={30} color="white"></Foundation>
                        </Button>
                        <Button style={{ backgroundColor: '#DD5144' }}
                            onPress={() =>
                                Alert.alert(
                                    'Delete current picture?',
                                    '',
                                    [{
                                        text: 'Cancel',
                                        onPress: () => { },
                                        style: 'cancel',
                                    },
                                    { text: 'OK', onPress: () => confirmDelete() },
                                    ],
                                    { cancelable: true },
                                )
                            }>
                            <MaterialIcons name='delete' size={30} color="white" />
                        </Button>
                    </Fab>
                }
            </View>

            {openGridView ? null :
                <Footer>
                    <FooterTab>
                        <Button active onPress={() => previousPic()}>
                            <Text>Previous</Text>
                        </Button>
                        <Button active onPress={() => nextPic()}>
                            <Text>Next</Text>
                        </Button>
                    </FooterTab>
                </Footer>
            }

            {openGridView ?
                <View style={{
                    position: 'absolute',
                    bottom: 0,
                    right: 0,
                    left: 0,
                    top: 0,
                    backgroundColor: 'white',
                    zIndex: 5,
                }}>
                    <Header style={{ marginTop: 25 }}>
                        <Left>
                            <Button transparent onPress={() => setopenGridView(false)}>
                                <Ionicons name='ios-arrow-round-back' size={40} color="white"></Ionicons>
                            </Button>
                        </Left>
                        <Body style={{ alignItems: 'center' }}>
                            <Title>Gallary</Title>
                        </Body>
                        <Right>
                            {selectedPic.length > 0 ?
                                <Button transparent onPress={() =>
                                    Alert.alert(
                                        'Delete selected pictures?',
                                        '',
                                        [{
                                            text: 'Cancel',
                                            onPress: () => { },
                                            style: 'cancel',
                                        },
                                        { text: 'OK', onPress: () => deletePics() },
                                        ],
                                        { cancelable: true },
                                    )}>
                                    <MaterialIcons name='delete' size={40} color="white" />
                                </Button>
                                : null}
                        </Right>
                    </Header>
                    <ScrollView>
                        {gallaryPic.length > 0 ?
                            <Grid>
                                <Col>
                                    {gallaryPic.map((item, index) => {
                                        const { id, uri } = item
                                        return (
                                            index % 2 === 0 ?
                                                <Row key={id} style={{ justifyContent: 'center', marginVertical: 5 }}>
                                                    <Button transparent
                                                        style={{
                                                            height: picWidth, width: picWidth, borderColor: 'green',
                                                            borderWidth: selectedPic.includes(id) ? 2 : 0
                                                        }}
                                                        onPress={() => togglePicHighlight(id)}
                                                        onLongPress={() => picLongPress(index)}>
                                                        <Image style={{ height: '100%', width: '100%', resizeMode: 'cover' }}
                                                            source={{ uri: uri }} />
                                                    </Button>
                                                </Row>
                                                : null)
                                    })}
                                </Col>
                                <Col>
                                    {gallaryPic.map((item, index) => {
                                        const { id, uri } = item
                                        return (
                                            index % 2 === 1 ?
                                                <Row key={id} style={{ justifyContent: 'center', marginVertical: 5 }}>
                                                    <Button transparent
                                                        style={{
                                                            height: picWidth, width: picWidth, borderColor: 'green',
                                                            borderWidth: selectedPic.includes(id) ? 2 : 0
                                                        }}
                                                        onPress={() => togglePicHighlight(id)}
                                                        onLongPress={() => picLongPress(index)}>
                                                        <Image style={{ height: '100%', width: '100%', resizeMode: 'cover' }}
                                                            source={{ uri: uri }} />
                                                    </Button>
                                                </Row>
                                                : null)
                                    })}
                                </Col>
                            </Grid>
                            : null}
                    </ScrollView>
                </View> : null}
        </Container>
    )
}

reference:
https://forums.expo.io/t/a-possible-way-to-show-a-share-menu-with-expo-without-detaching/9125/4
https://docs.expo.io/versions/latest/sdk/sharing/
https://docs.nativebase.io/Components.html#fabs-def-headref
https://stackoverflow.com/questions/53423855/share-images-and-files-on-react-native-using-expo
https://www.npmjs.com/package/react-native-zip-archive
https://chuanshuoge2.blogspot.com/2020/02/expo-image-viewer.html

No comments:

Post a Comment