1import { StackScreenProps } from '@react-navigation/stack'; 2import * as MediaLibrary from 'expo-media-library'; 3import React from 'react'; 4import { Image, ScrollView, StyleSheet, View, Alert } from 'react-native'; 5 6import Button from '../../components/Button'; 7import HeadingText from '../../components/HeadingText'; 8import MonoText from '../../components/MonoText'; 9 10const EXPO_ALBUM_NAME = 'Expo'; 11 12type Links = { 13 MediaDetails: { asset: MediaLibrary.Asset; onGoBack: () => void; album: MediaLibrary.Album }; 14}; 15 16type Props = StackScreenProps<Links, 'MediaDetails'>; 17 18export default class MediaDetailsScreen extends React.Component<Props> { 19 static navigationOptions = { 20 title: 'MediaLibrary Asset', 21 }; 22 23 state = { 24 details: null, 25 detailsWithoutDownloadingFromNetwork: null, 26 }; 27 28 componentDidMount() { 29 const { asset } = this.props.route.params; 30 MediaLibrary.getAssetInfoAsync(asset, { shouldDownloadFromNetwork: false }).then(details => { 31 this.setState({ detailsWithoutDownloadingFromNetwork: details }); 32 }); 33 MediaLibrary.getAssetInfoAsync(asset).then(details => { 34 this.setState({ details }); 35 }); 36 } 37 38 goBack() { 39 const { navigation, route } = this.props; 40 const { onGoBack } = route.params; 41 42 if (onGoBack) { 43 onGoBack(); 44 } 45 navigation.goBack(); 46 } 47 48 deleteAsset = async () => { 49 const { asset } = this.props.route.params!; 50 51 await MediaLibrary.deleteAssetsAsync([asset]); 52 this.goBack(); 53 }; 54 55 addToAlbum = async () => { 56 const permissions = await MediaLibrary.getPermissionsAsync(); 57 if (permissions?.accessPrivileges && permissions.accessPrivileges !== 'all') { 58 Alert.alert('Access to all photos is required to do this operation'); 59 return; 60 } 61 62 const { asset } = this.props.route.params!; 63 const expoAlbum = await MediaLibrary.getAlbumAsync(EXPO_ALBUM_NAME); 64 65 if (expoAlbum) { 66 await MediaLibrary.addAssetsToAlbumAsync(asset, expoAlbum); 67 } else { 68 await MediaLibrary.createAlbumAsync(EXPO_ALBUM_NAME, asset); 69 } 70 71 alert('Successfully added asset to Expo album!'); 72 }; 73 74 removeFromAlbum = async () => { 75 const { asset, album } = this.props.route.params!; 76 77 if (album) { 78 await MediaLibrary.removeAssetsFromAlbumAsync(asset.id, album.id); 79 this.goBack(); 80 } 81 }; 82 83 renderAsset(asset: MediaLibrary.Asset) { 84 const aspectRatio = asset.height ? asset.width / asset.height : 1; 85 86 switch (asset.mediaType) { 87 case MediaLibrary.MediaType.photo: 88 case MediaLibrary.MediaType.video: // TODO: render Expo.Video component 89 return ( 90 <Image 91 style={[styles.image, { aspectRatio }]} 92 source={{ uri: asset.uri }} 93 resizeMode="cover" 94 /> 95 ); 96 default: 97 return null; 98 } 99 } 100 101 render() { 102 const { details, detailsWithoutDownloadingFromNetwork } = this.state; 103 const { asset, album } = this.props.route.params!; 104 105 return ( 106 <ScrollView style={styles.container}> 107 <View style={styles.buttons}> 108 <Button 109 style={styles.button} 110 buttonStyle={{ backgroundColor: 'red' }} 111 title="Delete asset" 112 onPress={this.deleteAsset} 113 /> 114 {album && ( 115 <Button 116 style={styles.button} 117 buttonStyle={{ backgroundColor: 'red' }} 118 title={`Remove from ${album.title} album`} 119 onPress={this.removeFromAlbum} 120 /> 121 )} 122 </View> 123 {(!album || album.title !== EXPO_ALBUM_NAME) && ( 124 <View style={styles.buttons}> 125 <Button style={styles.button} title="Add to Expo album" onPress={this.addToAlbum} /> 126 </View> 127 )} 128 129 <View style={styles.imageContainer}>{this.renderAsset(asset)}</View> 130 131 <HeadingText>Base asset data</HeadingText> 132 <MonoText>{JSON.stringify(asset, null, 2)}</MonoText> 133 134 {details && ( 135 <View style={styles.details}> 136 <HeadingText>MediaLibrary.getAssetInfoAsync(assetId)</HeadingText> 137 <MonoText>{JSON.stringify(details, null, 2)}</MonoText> 138 </View> 139 )} 140 141 {detailsWithoutDownloadingFromNetwork && ( 142 <View style={styles.details}> 143 <HeadingText>{`MediaLibrary.getAssetInfoAsync(assetId, { shouldDownloadFromNetwork: false })`}</HeadingText> 144 <MonoText>{JSON.stringify(detailsWithoutDownloadingFromNetwork, null, 2)}</MonoText> 145 </View> 146 )} 147 </ScrollView> 148 ); 149 } 150} 151 152const styles = StyleSheet.create({ 153 container: { 154 paddingHorizontal: 10, 155 paddingVertical: 16, 156 flex: 1, 157 }, 158 buttons: { 159 marginBottom: 10, 160 flexDirection: 'row', 161 justifyContent: 'center', 162 alignItems: 'center', 163 }, 164 button: { 165 marginHorizontal: 5, 166 }, 167 imageContainer: { 168 width: '100%', 169 paddingVertical: 10, 170 paddingHorizontal: 25, 171 justifyContent: 'center', 172 }, 173 image: { 174 flex: 1, 175 }, 176 details: { 177 marginBottom: 10, 178 }, 179}); 180