Merge pull request #2178 from ecency/nt/multiple-media-selection

Nt/multiple media selection
This commit is contained in:
Feruz M 2022-02-03 20:44:54 +02:00 committed by GitHub
commit 2d96bd449b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 175 additions and 56 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { View, TouchableOpacity } from 'react-native';
import styles from './checkboxStyles';
@ -6,6 +6,10 @@ import styles from './checkboxStyles';
const CheckBoxView = ({ clicked, value, isChecked, style, locked }) => {
const [isCheck, setIsCheck] = useState(false);
useEffect(() => {
setIsCheck(isChecked);
}, [isChecked]);
const _checkClicked = () => {
setIsCheck(!isCheck);

View File

@ -0,0 +1,23 @@
import {replaceBetween } from './utils';
export default async ({ text, selection, setTextAndSelection, items }) => {
const imagePrefix = '!';
let newText = text;
let newSelection = selection;
items.forEach(item => {
if(item.url && item.text){
const formatedText = `\n${imagePrefix}[${item.text}](${item.url})\n`
newText = replaceBetween(newText, newSelection, formatedText);
const newIndex = newText && newText.indexOf(item.url, newSelection.start) + item.url.length + 2;
newSelection = {
start: newIndex,
end: newIndex
}
}
});
setTextAndSelection({ text: newText, selection: newSelection });
};

View File

@ -16,7 +16,7 @@ import { Icon } from '../../icon';
// Utils
import Formats from './formats/formats';
import applyImageLink from './formats/applyWebLinkFormat';
import applyMediaLink from './formats/applyMediaLink';
// Actions
import { toggleAccountsBottomSheet } from '../../../redux/actions/uiAction';
@ -147,12 +147,11 @@ const MarkdownEditorView = ({
useEffect(() => {
if (uploadedImage && uploadedImage.url) {
if (uploadedImage.shouldInsert) {
applyImageLink({
applyMediaLink({
text,
selection,
setTextAndSelection: _setTextAndSelection,
item: { url: uploadedImage.url, text: uploadedImage.hash },
isImage: !!uploadedImage,
items: [{ url: uploadedImage.url, text: uploadedImage.hash }],
});
} else {
uploadsGalleryModalRef.current.showModal();
@ -265,14 +264,18 @@ const MarkdownEditorView = ({
});
};
const _handleOnMediaSelect = (mediaInsert) => {
if (mediaInsert && mediaInsert.url) {
applyImageLink({
const _handleOnMediaSelect = (mediaArray) => {
const items = mediaArray.map((mediaInsert) => ({
url: mediaInsert.url,
text: mediaInsert.hash,
}));
if (items.length) {
applyMediaLink({
text,
selection,
setTextAndSelection: _setTextAndSelection,
item: { url: mediaInsert.url, text: mediaInsert.hash },
isImage: !!mediaInsert,
items,
});
}
};

View File

@ -2,12 +2,13 @@ import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'rea
import { useIntl } from 'react-intl';
import {Text, View, FlatList, RefreshControl, TouchableOpacity, Alert, Platform } from 'react-native';
import FastImage from 'react-native-fast-image';
import { IconButton } from '..';
import { CheckBox, IconButton, MainButton, TextButton } from '..';
import { UploadedMedia } from '../../models';
import { addImage, deleteImage, getImages } from '../../providers/ecency/ecency';
import Modal from '../modal';
import styles from './uploadsGalleryModalStyles';
import { proxifyImageSrc } from '@ecency/render-helper';
import {View as AnimatedView} from 'react-native-animatable';
export interface UploadsGalleryModalRef {
@ -21,7 +22,7 @@ interface MediaInsertData {
interface UploadsGalleryModalProps {
username:string;
handleOnSelect:(data:MediaInsertData)=>void;
handleOnSelect:(data:Array<MediaInsertData>)=>void;
uploadedImage:MediaInsertData;
}
@ -30,7 +31,8 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa
const [mediaUploads, setMediaUploads] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [showModal, setShowModal] = useState(false);
const [showModal, setShowModal] = useState(false);
const [indices, setIndices] = useState<Map<number, boolean>>(new Map());
useImperativeHandle(ref, () => ({
@ -44,6 +46,12 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa
_getMediaUploads();
}, []);
useEffect(()=>{
if(!showModal){
setIndices(new Map());
}
}, [showModal])
useEffect(() => {
if(uploadedImage){
_addUploadedImageToGallery();
@ -67,11 +75,14 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa
// remove image data from user's gallery
const _deleteMediaItem = async (id:string) => {
const _deleteMedia = async () => {
try{
setIsLoading(true);
await deleteImage(id)
for (const index of indices.keys()) {
await deleteImage(mediaUploads[index]._id)
}
await _getMediaUploads();
setIndices(new Map());
setIsLoading(false);
} catch(err){
console.warn("failed to remove image from gallery", err)
@ -92,45 +103,111 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa
setIsLoading(false);
}
}catch(err){
console.warn("Failed to get snippets")
console.warn("Failed to get images")
setIsLoading(false);
}
}
//render list item for snippet and handle actions;
const _renderItem = ({ item }:{item:UploadedMedia, index:number}) => {
const _onPress = () => {
//inserts media items in post body
const _insertMedia = async (selectedIndex?:number) => {
//TODO: debug why insert not working
const map = selectedIndex ? new Map([[selectedIndex, true]]) : indices;
const data = {
url:item.url,
hash:item.url.split('/').pop()
}
const data = []
for (const index of map.keys()) {
console.log(index)
const item = mediaUploads[index]
data.push({
url:item.url,
hash:item.url.split('/').pop()
})
}
handleOnSelect(data)
setShowModal(false);
}
const _onRemovePress = async () => {
const _onConfirm = () => {
_deleteMediaItem(item._id)
//renders footer with add snipept button and shows new snippet modal
const _renderFloatingPanel = () => {
if(!indices.size){
return null
}
const _onRemovePress = async () => {
const _onConfirm = () => {
_deleteMedia()
}
Alert.alert(
intl.formatMessage({id:'alert.delete'}),
intl.formatMessage({id:'alert.remove_alert'}),
[{
text:intl.formatMessage({id:'alert.cancel'}),
style:'cancel'
},{
text:intl.formatMessage({id:'alert.confirm'}),
onPress:_onConfirm
}]
)
}
return (
<AnimatedView animation={"slideInUp"} duration={300}>
<View style={styles.floatingContainer}>
<TextButton
style={styles.cancelButton}
onPress={_onRemovePress}
text={intl.formatMessage({
id: 'uploads_modal.btn_delete',
})}
/>
<MainButton
style={{ width: 136, marginLeft:12}}
onPress={_insertMedia}
iconName="plus"
iconType="MaterialCommunityIcons"
iconColor="white"
text={intl.formatMessage({
id: 'uploads_modal.btn_insert',
})}
/>
</View>
</AnimatedView>
);
};
//render list item for snippet and handle actions;
const _renderItem = ({ item, index }:{item:UploadedMedia, index:number}) => {
const _onCheckPress = () => {
//update selection indices
if(indices.has(index)){
indices.delete(index);
}else {
indices.set(index, true);
}
Alert.alert(
intl.formatMessage({id:'alert.delete'}),
intl.formatMessage({id:'alert.remove_alert'}),
[{
text:intl.formatMessage({id:'alert.cancel'}),
style:'cancel'
},{
text:intl.formatMessage({id:'alert.confirm'}),
onPress:_onConfirm
}]
)
setIndices(new Map([...indices]));
}
const _onPress = () => {
if(indices.size){
_onCheckPress()
}else {
_insertMedia(index)
}
}
const thumbUrl = proxifyImageSrc(item.url, 600, 500, Platform.OS === 'ios' ? 'match' : 'webp');
return (
@ -139,14 +216,11 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa
source={{uri:thumbUrl}}
style={styles.mediaItem}
/>
<View style={styles.removeItemContainer}>
<IconButton
iconStyle={styles.itemIcon}
style={styles.itemIconWrapper}
iconType="MaterialCommunityIcons"
name="delete"
onPress={_onRemovePress}
size={20}
<View style={styles.checkContainer}>
<CheckBox
isChecked={indices.has(index)}
clicked={_onCheckPress}
style={styles.checkStyle}
/>
</View>
@ -176,6 +250,7 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa
keyExtractor={(item) => `item_${item.url}`}
renderItem={_renderItem}
ListEmptyComponent={_renderEmptyContent}
extraData={indices}
numColumns={2}
refreshControl={
<RefreshControl
@ -185,6 +260,7 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa
}
/>
</View>
{_renderFloatingPanel()}
</View>
)

View File

@ -22,11 +22,17 @@ export default EStyleSheet.create({
paddingHorizontal:16
},
floatingContainer:{
flexDirection:'row',
position:'absolute',
bottom:0,
right:20,
right:0,
left: 0,
justifyContent:'flex-end',
zIndex:10
alignItems:'center',
zIndex:10,
paddingVertical:16,
paddingHorizontal: 24,
backgroundColor:'$primaryBackgroundColor'
} as ViewStyle,
mediaItem:{
@ -95,9 +101,14 @@ export default EStyleSheet.create({
} as ViewStyle,
removeItemContainer:{
checkContainer:{
position:'absolute',
top:16,
right:16
} as ViewStyle
})
bottom:20,
right:20
} as ViewStyle,
checkStyle:{
backgroundColor:'$white',
} as ViewStyle,
})

View File

@ -363,6 +363,8 @@
"title":"Uploaded Images",
"title_remove_confirmation":"Delete image",
"btn_add":"Image",
"btn_insert":"INSERT",
"btn_delete":"DELETE",
"message_failed":"Failed to upload image"
},
"pincode": {