Files
notesnook/apps/mobile/src/components/SelectionWrapper/index.js

398 lines
11 KiB
JavaScript
Raw Normal View History

2020-12-20 23:15:37 +05:00
import React, { useEffect, useState } from 'react';
import { TouchableOpacity, View } from 'react-native';
2020-02-11 20:33:36 +05:00
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
2020-12-20 23:15:37 +05:00
import { useTracked } from '../../provider';
import { Actions } from '../../provider/Actions';
import { eSendEvent, openVault } from '../../services/EventManager';
import { getElevation } from '../../utils';
import { hexToRGBA } from '../../utils/ColorUtils';
import { db } from '../../utils/DB';
import { refreshNotesPage } from '../../utils/Events';
import { SIZE } from '../../utils/SizeUtils';
import { ActionIcon } from '../ActionIcon';
import { Button } from '../Button';
import { simpleDialogEvent } from '../DialogManager/recievers';
import { TEMPLATE_PERMANANT_DELETE } from '../DialogManager/Templates';
import { PressableButton } from '../PressableButton';
2020-12-16 20:01:02 +05:00
import Heading from '../Typography/Heading';
const Filler = ({item, background}) => {
const [state] = useTracked();
const {colors, currentEditingNote} = state;
const color = item.color || 'accent';
return (
<View
style={{
position: 'absolute',
width: '110%',
height: '110%',
paddingVertical: '3.5%',
paddingHorizontal: '5%',
alignItems: 'flex-end',
justifyContent: 'flex-end',
}}>
<View
style={{
flexDirection: 'row',
}}>
{item.conflicted ? (
<View
style={{
backgroundColor: hexToRGBA(colors.red, 0.12),
paddingHorizontal: 3,
paddingVertical: 2,
borderRadius: 3,
marginRight: 10,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
}}>
<Icon name="alert-circle" size={SIZE.xxs} color={colors.red} />
<Heading
size={SIZE.xxs}
style={{
color: colors.red,
marginLeft: 5,
}}>
CONFLICTS
</Heading>
</View>
) : null}
{currentEditingNote === item.id ? (
<View
style={{
backgroundColor: hexToRGBA(colors[color], 0.12),
paddingHorizontal: 3,
paddingVertical: 2,
borderRadius: 3,
marginRight: 10,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
}}>
<Icon name="pencil-outline" size={SIZE.xxs} color={colors[color]} />
<Heading
size={SIZE.xxs}
style={{marginLeft: 5}}
color={colors[color]}>
EDITING NOW
</Heading>
</View>
) : null}
</View>
</View>
);
};
2020-02-06 23:38:40 +05:00
2020-12-20 17:38:28 +05:00
const ActionStrip = ({note, setActionStrip}) => {
const [state, dispatch] = useTracked();
const {colors, selectionMode} = state;
const [isPinnedToMenu, setIsPinnedToMenu] = useState(false);
useEffect(() => {
if (note.type === 'note') return;
setIsPinnedToMenu(db.settings.isPinned(note.id));
}, []);
const updateNotes = () => {
dispatch({type: Actions.NOTES});
dispatch({type: Actions.FAVORITES});
eSendEvent(refreshNotesPage);
};
const actions = [
{
icon: note.pinned ? 'pin-off' : 'pin',
2020-12-28 16:16:50 +05:00
visible:note.type === "note" || note.type === "notebook",
2020-12-20 17:38:28 +05:00
onPress: async () => {
if (!note.id) return;
if (note.type === 'note') {
if (db.notes.pinned.length === 3) {
ToastEvent.show('You cannot pin more than 3 notes', 'error');
return;
}
await db.notes.note(note.id).pin();
} else {
if (db.notebooks.pinned.length === 3) {
ToastEvent.show('You cannot pin more than 3 notebooks', 'error');
return;
}
await db.notebooks.notebook(note.id).pin();
dispatch({type: Actions.NOTEBOOKS});
}
updateNotes();
setActionStrip(false);
},
},
{
icon: note.favorite ? 'star-off' : 'star',
onPress: async () => {
if (!note.id) return;
if (note.type === 'note') {
await db.notes.note(note.id).favorite();
} else {
await db.notebooks.notebook(note.id).favorite();
}
updateNotes();
setActionStrip(false);
},
visible: note.type === 'note',
color: !note.favorite ? 'orange' : null,
},
{
name: isPinnedToMenu ? 'Unpin from Menu' : 'Pin to Menu',
icon: 'tag-outline',
func: async () => {
try {
if (isPinnedToMenu) {
await db.settings.unpin(note.id);
ToastEvent.show('Unpinned from menu', 'success');
} else {
if (item.type === 'topic') {
await db.settings.pin(note.type, {
id: note.id,
notebookId: note.notebookId,
});
} else {
await db.settings.pin(note.type, {id: note.id});
}
ToastEvent.show('Pinned to menu', 'success');
}
setIsPinnedToMenu(db.settings.isPinned(note.id));
dispatch({type: Actions.MENU_PINS});
} catch (e) {}
},
visible: note.type !== 'note',
},
{
icon: 'content-copy',
visible: note.type === 'note',
onPress: async () => {
if (note.locked) {
openVault({
copyNote: true,
novault: true,
locked: true,
item: note,
});
} else {
let text = await db.notes.note(note.id).content();
text = toTXT(text);
text = `${note.title}\n \n ${text}`;
Clipboard.setString(text);
ToastEvent.show('Note copied to clipboard', 'success');
}
setActionStrip(false);
},
},
{
icon: 'delete-restore',
onPress: async () => {
await db.trash.restore(note.id);
dispatch({type: Actions.TRASH});
dispatch({type: note.itemType});
dispatch({type: Actions.FAVORITES});
eSendEvent(refreshNotesPage);
ToastEvent.show(
item.type === 'note' ? 'Note restored' : 'Notebook restored',
'success',
);
setActionStrip(false);
},
visible: note.type === 'trash',
},
{
icon: 'delete',
visible: note.type === 'trash',
onPress: () => {
simpleDialogEvent(TEMPLATE_PERMANANT_DELETE);
setActionStrip(false);
},
},
{
icon: 'delete',
visible: note.type !== 'trash',
onPress: async () => {
try {
await deleteItems(note);
} catch (e) {
console.log(e);
}
setActionStrip(false);
},
},
{
icon: 'close',
onPress: () => setActionStrip(false),
color: colors.light,
bg: colors.red,
visible: true,
},
];
return (
<View
style={{
position: 'absolute',
zIndex: 10,
width: '102%',
height: '100%',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
}}>
<Button
type="accent"
title="Select"
icon="check"
onPress={() => {
if (!selectionMode) {
dispatch({type: Actions.SELECTION_MODE, enabled: true});
}
dispatch({type: Actions.SELECTED_ITEMS, item: note});
setActionStrip(false);
}}
style={{
borderRadius: 100,
paddingHorizontal: 12,
...getElevation(5),
}}
height={30}
/>
{actions.map(
(item) =>
item.visible && (
<View
key={item.icon}
style={{
width: 40,
height: 40,
2020-12-20 23:15:37 +05:00
backgroundColor: item.bg || colors.nav,
2020-12-20 17:38:28 +05:00
borderRadius: 100,
justifyContent: 'center',
alignItems: 'center',
...getElevation(5),
marginLeft: 15,
}}>
<ActionIcon
color={item.color || colors.heading}
onPress={item.onPress}
name={item.icon}
size={SIZE.lg}
/>
</View>
),
)}
</View>
);
};
2020-03-18 12:31:06 +05:00
const SelectionWrapper = ({
children,
item,
index,
background,
2020-09-09 14:55:59 +05:00
onLongPress,
2020-09-09 22:09:57 +05:00
onPress,
2020-12-16 12:07:34 +05:00
testID,
2020-03-18 12:31:06 +05:00
}) => {
2020-01-17 21:26:01 +05:00
const [state, dispatch] = useTracked();
2020-12-16 20:01:02 +05:00
const {colors, selectionMode, selectedItemsList} = state;
2020-01-31 18:22:20 +05:00
const [selected, setSelected] = useState(false);
2020-12-20 17:38:28 +05:00
const [actionStrip, setActionStrip] = useState(false);
2020-01-31 18:22:20 +05:00
useEffect(() => {
2020-12-20 17:38:28 +05:00
if (selectionMode) {
setActionStrip(false);
let exists = selectedItemsList.filter(
(o) => o.dateCreated === item.dateCreated,
);
2020-01-31 18:22:20 +05:00
2020-12-20 17:38:28 +05:00
if (exists[0]) {
if (!selected) {
setSelected(true);
}
} else {
if (selected) {
setSelected(false);
}
2020-01-31 18:22:20 +05:00
}
}
}, [selectedItemsList]);
2020-01-17 00:23:16 +05:00
return (
2020-09-09 14:55:59 +05:00
<PressableButton
2020-12-16 20:01:02 +05:00
customColor="transparent"
2020-12-01 22:52:01 +05:00
testID={testID}
2020-12-20 17:38:28 +05:00
onLongPress={() => {
if (selectionMode) return;
setActionStrip(!actionStrip);
}}
2020-09-09 14:55:59 +05:00
onPress={onPress}
2020-12-16 20:01:02 +05:00
customSelectedColor={colors.nav}
2020-12-06 14:42:46 +05:00
customAlpha={!colors.night ? -0.02 : 0.02}
2020-12-16 20:01:02 +05:00
customOpacity={1}
2020-09-09 14:55:59 +05:00
customStyle={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
2020-01-22 02:51:24 +05:00
width: '100%',
2020-09-18 20:54:31 +05:00
borderRadius: 0,
2020-12-16 20:01:02 +05:00
overflow: 'hidden',
2020-12-20 17:38:28 +05:00
paddingHorizontal: 12,
2020-03-18 12:31:06 +05:00
marginTop:
2020-11-14 10:06:41 +05:00
index === 0 && !selectionMode
2020-03-18 12:31:06 +05:00
? 15
2020-11-14 10:06:41 +05:00
: index === 0 && selectionMode
2020-03-18 12:31:06 +05:00
? 30
: 0,
}}>
2020-12-20 17:38:28 +05:00
{actionStrip && (
<ActionStrip note={item} setActionStrip={setActionStrip} />
)}
{item.type === 'note' && <Filler background={background} item={item} />}
2020-03-18 12:31:06 +05:00
2020-01-22 02:51:24 +05:00
<View
style={{
display: selectionMode ? 'flex' : 'none',
2020-01-17 00:23:16 +05:00
opacity: selectionMode ? 1 : 0,
2020-01-31 18:40:56 +05:00
width: '10%',
height: 70,
justifyContent: 'center',
alignItems: 'center',
paddingRight: 8,
}}>
2020-12-16 12:07:34 +05:00
{item.title !== 'General' && (
<TouchableOpacity
activeOpacity={1}
onPress={onLongPress}
style={{
justifyContent: 'center',
alignItems: 'center',
height: 70,
}}>
<Icon
size={SIZE.lg}
color={selected ? colors.accent : colors.icon}
name={
selected
? 'check-circle-outline'
: 'checkbox-blank-circle-outline'
}
/>
</TouchableOpacity>
)}
2020-01-22 02:51:24 +05:00
</View>
2020-02-06 23:38:40 +05:00
{children}
2020-09-09 14:55:59 +05:00
</PressableButton>
);
};
export default SelectionWrapper;