added support for gallery modal

This commit is contained in:
Nouman Tahir 2021-04-04 00:58:17 +05:00
parent 97df283214
commit 0d837f9bf3
9 changed files with 354 additions and 16 deletions

View File

@ -4,6 +4,7 @@ import { BasicHeader } from './basicHeader';
import { BoostIndicatorAnimation, PulseAnimation, SpinIndicator } from './animations';
import BeneficiaryModal from './beneficiaryModal/beneficiaryModal';
import SnippetsModal from './snippetsModal/snippetsModal';
import { UploadsGalleryModal } from './uploadsGalleryModal/uploadsGalleryModal';
import { BottomTabBar } from './bottomTabBar';
import { CheckBox } from './checkbox';
import { CircularButton, TextButton, SquareButton } from './buttons';
@ -183,6 +184,7 @@ export {
SettingsItem,
SideMenu,
SnippetsModal,
UploadsGalleryModal,
SpinGame,
SpinIndicator,
SquareButton,

View File

@ -33,6 +33,7 @@ import {
SummaryArea,
Modal,
SnippetsModal,
UploadsGalleryModal,
} from '../../index';
import { ThemeContainer } from '../../../containers';
@ -75,6 +76,7 @@ const MarkdownEditorView = ({
const inputRef = useRef(null);
const galleryRef = useRef(null);
const clearRef = useRef(null);
const uploadsGalleryModalRef = useRef(null);
const dispatch = useDispatch();
const isVisibleAccountsBottomSheet = useSelector(
@ -105,17 +107,17 @@ const MarkdownEditorView = ({
}
}, [isLoading]);
useEffect(() => {
if (uploadedImage && uploadedImage.url) {
applyImageLink({
text,
selection,
setTextAndSelection: _setTextAndSelection,
item: { url: uploadedImage.url, text: uploadedImage.hash },
isImage: !!uploadedImage,
});
}
}, [uploadedImage]);
// useEffect(() => {
// if (uploadedImage && uploadedImage.url) {
// applyImageLink({
// text,
// selection,
// setTextAndSelection: _setTextAndSelection,
// item: { url: uploadedImage.url, text: uploadedImage.hash },
// isImage: !!uploadedImage,
// });
// }
// }, [uploadedImage]);
useEffect(() => {
setText(draftBody);
@ -213,6 +215,18 @@ const MarkdownEditorView = ({
});
};
const _handleOnMediaSelect = (mediaInsert) => {
if (mediaInsert && mediaInsert.url) {
applyImageLink({
text,
selection,
setTextAndSelection: _setTextAndSelection,
item: { url: mediaInsert.url, text: mediaInsert.hash },
isImage: !!mediaInsert,
});
}
};
const _renderMarkupButton = ({ item }) => (
<View style={styles.buttonWrapper}>
<IconButton
@ -258,7 +272,10 @@ const MarkdownEditorView = ({
name="text-short"
/>
<IconButton
onPress={() => galleryRef.current.show()}
onPress={() => {
// galleryRef.current.show()}
uploadsGalleryModalRef.current.showModal();
}}
style={styles.rightIcons}
size={20}
iconStyle={styles.icon}
@ -374,6 +391,18 @@ const MarkdownEditorView = ({
>
<SnippetsModal username={currentAccount.username} handleOnSelect={_handleOnSnippetSelect} />
</Modal>
<UploadsGalleryModal
ref={uploadsGalleryModalRef}
username={currentAccount.username}
handleOnSelect={_handleOnMediaSelect}
handleOnUploadPress={() => {
galleryRef.current.show();
}}
isUploading={isLoading}
uploadedImage={uploadedImage}
/>
<ActionSheet
ref={galleryRef}
options={[

View File

@ -0,0 +1,191 @@
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { useIntl } from 'react-intl';
import {Text, View, FlatList, RefreshControl, TouchableOpacity, Alert, Platform } from 'react-native';
import FastImage from 'react-native-fast-image';
import { MainButton } from '..';
import { UploadedMedia } from '../../models';
import { addMyImage, getImages } from '../../providers/ecency/ecency';
import Modal from '../modal';
import styles from './uploadsGalleryModalStyles';
import { proxifyImageSrc } from '@ecency/render-helper';
export interface UploadsGalleryModalRef {
showModal:()=>void;
}
interface MediaInsertData {
url:string,
hash:string,
}
interface UploadsGalleryModalProps {
username:string;
isUploading:boolean;
handleOnSelect:(data:MediaInsertData)=>void;
handleOnUploadPress:()=>void;
uploadedImage:MediaInsertData;
}
export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, handleOnUploadPress, isUploading, uploadedImage}: UploadsGalleryModalProps, ref) => {
const intl = useIntl();
const [mediaUploads, setMediaUploads] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [showModal, setShowModal] = useState(false);
useImperativeHandle(ref, () => ({
showModal: () => {
setShowModal(true);
},
}));
useEffect(() => {
_getMediaUploads();
}, []);
useEffect(() => {
if(uploadedImage){
_addUploadedImageToGallery();
}
}, [uploadedImage])
const _addUploadedImageToGallery = async () => {
try{
console.log("adding image to gallery",username, uploadedImage )
setIsLoading(true);
await addMyImage(username, uploadedImage.url);
_getMediaUploads();
setIsLoading(false);
}catch(err){
console.warn("Failed to get snippets", err)
setIsLoading(false);
}
}
//fetch snippets from server
const _getMediaUploads = async () => {
try{
if (username) {
setIsLoading(true);
console.log("getting images for: " + username )
const images = await getImages(username)
console.log("images received", images)
setMediaUploads(images);
setIsLoading(false);
}
}catch(err){
console.warn("Failed to get snippets")
setIsLoading(false);
}
}
//render list item for snippet and handle actions;
const _renderItem = ({ item, index }:{item:UploadedMedia, index:number}) => {
const _onPress = () => {
const data = {
url:item.url,
hash:item.url.split('/').pop()
}
handleOnSelect(data)
setShowModal(false);
}
const thumbUrl = proxifyImageSrc(item.url, 600, 500, Platform.OS === 'ios' ? 'match' : 'webp');
return (
<TouchableOpacity onPress={_onPress}>
<FastImage
source={{uri:thumbUrl}}
style={styles.mediaItem}
/>
</TouchableOpacity>
)
};
//render empty list placeholder
const _renderEmptyContent = () => {
return (
<>
<Text style={styles.title}>{intl.formatMessage({id:'uploads_modal.label_no_images'})}</Text>
</>
);
};
//renders footer with add snipept button and shows new snippet modal
const _renderFloatingButton = () => {
const _onPress = () => {
if(handleOnUploadPress){
handleOnUploadPress();
}
}
return (
<View style={styles.floatingContainer}>
<MainButton
style={{ width: isUploading?null:130}}
onPress={_onPress}
iconName="plus"
iconType="MaterialCommunityIcons"
iconColor="white"
text={intl.formatMessage({id:'uploads_modal.btn_add'})}
isLoading={isUploading}
/>
</View>
);
};
const _renderContent = (
<View style={styles.container}>
<View style={styles.bodyWrapper}>
<FlatList
data={mediaUploads}
keyExtractor={(item) => `item_${item.url}`}
renderItem={_renderItem}
ListEmptyComponent={_renderEmptyContent}
numColumns={3}
refreshControl={
<RefreshControl
refreshing={isLoading}
onRefresh={_getMediaUploads}
/>
}
/>
{_renderFloatingButton()}
</View>
</View>
)
return (
<Modal
isOpen={showModal}
handleOnModalClose={() => setShowModal(false)}
isFullScreen
isCloseButton
presentationStyle="formSheet"
title={intl.formatMessage({
id:'uploads_modal.title'
})}
animationType="slide"
style={styles.modalStyle}
>
{_renderContent}
</Modal>
);
});

View File

@ -0,0 +1,87 @@
import { TextStyle, StyleSheet, ViewStyle, Dimensions, ImageStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
const gridItemWidth = ((Dimensions.get('window').width/3) - 28);
const gridItemHeight = (gridItemWidth * 500)/600
export default EStyleSheet.create({
modalStyle: {
flex: 1,
backgroundColor: '$primaryBackgroundColor',
margin: 0,
paddingTop: 32,
paddingBottom: 16,
},
container: {
flex: 1,
justifyContent: 'space-between',
paddingVertical: 8,
},
bodyWrapper: {
flex: 3,
paddingHorizontal:16
},
floatingContainer:{
position:'absolute',
bottom:0,
right:20,
justifyContent:'flex-end',
zIndex:10
} as ViewStyle,
mediaItem:{
margin:8,
height:gridItemHeight,
width:gridItemWidth,
borderRadius:16,
backgroundColor:'$primaryLightGray'
} as ImageStyle,
inputContainer:{
flex:1
} as ViewStyle,
titleInput:{
color: '$primaryBlack',
fontWeight: 'bold',
fontSize: 18,
textAlignVertical: 'top',
paddingVertical: 0,
backgroundColor:'$primaryBackgroundColor',
borderBottomWidth:StyleSheet.hairlineWidth,
borderBottomColor:'$primaryDarkGray'
} as TextStyle,
title: {
fontWeight: '700',
flex:1,
fontSize:16,
color:'$primaryBlack'
} as TextStyle,
btnText:{
color:'$pureWhite'
} as TextStyle,
saveButton:{
backgroundColor:'$primaryBlue',
width:150,
paddingVertical:16,
borderRadius:32,
justifyContent:'center',
alignItems:'center'
} as ViewStyle,
closeButton:{
marginRight:16,
paddingVertical:8,
borderRadius:16,
justifyContent:'center',
alignItems:'center'
} as ViewStyle,
actionPanel:{
flexDirection:'row',
justifyContent:'flex-end',
alignItems:'center',
marginBottom:16
} as ViewStyle,
})

View File

@ -331,6 +331,20 @@
"btn_confirm":"Confirm",
"btn_cancel":"Cancel"
},
"uploads_modal":{
"label_no_images":"No Images Found",
"title":"Uploaded Images",
"title_remove_confirmation":"Delete image",
"placeholder_title":"Snippet title",
"placeholder_body":"Add snippet body here...",
"btn_save":"SAVE",
"btn_close":"CLOSE",
"btn_add":"Image",
"message_failed":"Failed to upload image",
"message_remove_confirmation":"Are you sure you want to delete this image?",
"btn_confirm":"Confirm",
"btn_cancel":"Cancel"
},
"pincode": {
"enter_text": "Enter PIN to unlock",
"set_new": "Set new PIN",

View File

@ -1 +1,2 @@
export * from './snippet';
export * from './snippet';
export * from './media';

View File

@ -0,0 +1 @@
export * from './uploaded-media';

View File

@ -0,0 +1,6 @@
export interface UploadedMedia {
_id:string;
timestamp:number;
created:string;
url:string;
}

View File

@ -456,9 +456,16 @@ export const moveSchedule = (id, username) => api.put(`/schedules/${username}/${
export const getImages = (username) =>
api
.get(`api/images/${username}`)
.then((resp) => resp.data)
.catch((error) => bugsnag.notify(error));
.get(`/images/${username}`)
.then((resp) => {
const res = resp.data;
console.log('res: ', res);
return resp.data;
})
.catch((error) => {
console.warn('Failed to get images', error);
bugsnag.notify(error);
});
export const addMyImage = (user, url) =>
api.post('/image', {