mirror of
https://github.com/ecency/ecency-mobile.git
synced 2025-01-04 12:05:54 +03:00
added support for gallery modal
This commit is contained in:
parent
97df283214
commit
0d837f9bf3
@ -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,
|
||||
|
@ -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={[
|
||||
|
191
src/components/uploadsGalleryModal/uploadsGalleryModal.tsx
Normal file
191
src/components/uploadsGalleryModal/uploadsGalleryModal.tsx
Normal 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>
|
||||
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -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,
|
||||
|
||||
})
|
@ -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",
|
||||
|
@ -1 +1,2 @@
|
||||
export * from './snippet';
|
||||
export * from './snippet';
|
||||
export * from './media';
|
1
src/models/media/index.ts
Normal file
1
src/models/media/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './uploaded-media';
|
6
src/models/media/uploaded-media.ts
Normal file
6
src/models/media/uploaded-media.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface UploadedMedia {
|
||||
_id:string;
|
||||
timestamp:number;
|
||||
created:string;
|
||||
url:string;
|
||||
}
|
@ -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', {
|
||||
|
Loading…
Reference in New Issue
Block a user