import React, { useEffect, useState } from 'react';
import {
ActivityIndicator,
Clipboard,
Dimensions,
Keyboard,
ScrollView,
TouchableOpacity,
View
} from 'react-native';
import Share from 'react-native-share';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { notesnook } from '../../../e2e/test.ids';
import { useNoteStore, useTracked, useTrackedNotes } from '../../provider';
import { Actions } from '../../provider/Actions';
import { DDS } from '../../services/DeviceDetection';
import {
eSendEvent,
openVault,
sendNoteEditedEvent,
ToastEvent
} from '../../services/EventManager';
import Navigation from '../../services/Navigation';
import Sync from '../../services/Sync';
import { doInBackground, editing, toTXT } from '../../utils';
import {
ACCENT,
COLOR_SCHEME,
COLOR_SCHEME_DARK,
COLOR_SCHEME_LIGHT,
setColorScheme
} from '../../utils/Colors';
import { db } from '../../utils/DB';
import {
eOpenMoveNoteDialog
} from '../../utils/Events';
import { deleteItems } from '../../utils/functions';
import { MMKV } from '../../utils/mmkv';
import { opacity, pv, SIZE } from '../../utils/SizeUtils';
import { sleep, timeConverter } from '../../utils/TimeUtils';
import { PressableButton } from '../PressableButton';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
import { ActionSheetColorsSection } from './ActionSheetColorsSection';
import { ActionSheetTagsSection } from './ActionSheetTagsSection';
const w = Dimensions.get('window').width;
export const ActionSheetComponent = ({
close = () => {},
item,
hasColors = false,
hasTags = false,
rowItems = [],
columnItems = [],
getRef,
}) => {
const [state, dispatch] = useTracked();
const {colors, user, lastSynced} = state;
const [refreshing, setRefreshing] = useState(false);
const [isPinnedToMenu, setIsPinnedToMenu] = useState(false);
const [note, setNote] = useState(item);
const [noteInTopic, setNoteInTopic] = useState(
editing.actionAfterFirstSave.type === 'topic' &&
db.notebooks
.notebook(editing.actionAfterFirstSave.notebook)
.topics.topic(editing.actionAfterFirstSave.id)
.has(item.id),
);
function changeColorScheme(colors = COLOR_SCHEME, accent = ACCENT) {
let newColors = setColorScheme(colors, accent);
dispatch({type: Actions.THEME, colors: newColors});
}
useEffect(() => {
if (item.dateCreated !== null) {
setNote({...item});
if (item.type !== note) {
setIsPinnedToMenu(db.settings.isPinned(note.id));
}
}
}, [item]);
const localRefresh = (type, nodispatch = false) => {
if (!note || !note.id) return;
let toAdd;
switch (type) {
case 'note': {
toAdd = db.notes.note(note.id);
if (toAdd) {
toAdd = toAdd.data;
} else {
setTimeout(() => {
toAdd = db.notes.note(note.id);
if (toAdd) {
toAdd = toAdd.data;
}
}, 500);
}
break;
}
case 'notebook': {
toAdd = db.notebooks.notebook(note.id);
if (toAdd) {
toAdd = toAdd.data;
} else {
setTimeout(() => {
toAdd = db.notebooks.notebook(note.id);
if (toAdd) {
toAdd = toAdd.data;
}
}, 500);
}
break;
}
case 'topic': {
toAdd = db.notebooks.notebook(note.notebookId).topics.topic(note.title);
break;
}
}
if (!toAdd || !toAdd.id) return;
if (!nodispatch) {
dispatch({type: type});
if (type === 'note') {
Navigation.setRoutesToUpdate([
Navigation.routeNames.NotesPage,
Navigation.routeNames.Favorites,
Navigation.routeNames.Notes,
]);
}
}
setNote({...toAdd});
};
const rowItemsData = [
{
name: 'Add to',
icon: 'book-outline',
func: () => {
close();
dispatch({type: Actions.CLEAR_SELECTION});
dispatch({type: Actions.SELECTED_ITEMS, item: note});
setTimeout(() => {
eSendEvent(eOpenMoveNoteDialog, note);
}, 300);
},
},
{
name: 'Share',
icon: 'share-variant',
func: async () => {
if (note.locked) {
close();
openVault({
item: item,
novault: true,
locked: true,
share: true,
title: 'Share note',
description: 'Unlock note to share it.',
});
} else {
let text = await db.notes.note(note.id).export('txt');
let m = `${note.title}\n \n ${text}`;
Share.open({
title: 'Share note to',
failOnCancel: false,
message: m,
});
}
},
},
{
name: 'Export',
icon: 'export',
func: () => {
close('export');
},
},
{
name: 'Delete',
icon: 'delete',
func: async () => {
close();
if (note.locked) {
await sleep(300);
openVault({
deleteNote: true,
novault: true,
locked: true,
item: note,
title: 'Delete note',
description: 'Unlock note to delete it.',
});
} else {
try {
close();
await deleteItems(note);
} catch (e) {
//console.log(e);
}
}
},
},
{
name: 'Edit Notebook',
icon: 'square-edit-outline',
func: () => {
close('notebook');
},
},
{
name: 'Edit Topic',
icon: 'square-edit-outline',
func: () => {
close('topic');
},
},
{
name: 'Copy',
icon: 'content-copy',
func: async () => {
if (note.locked) {
openVault({
copyNote: true,
novault: true,
locked: true,
item: note,
title: 'Copy note',
description: 'Unlock note to copy to clipboard.',
});
} else {
let text = await db.notes.note(note.id).content();
text = toTXT(text);
text = `${note.title}\n \n ${text}`;
Clipboard.setString(text);
ToastEvent.show({
heading: 'Note copied to clipboard',
type: 'success',
context: 'local',
});
}
},
},
{
name: 'Restore',
icon: 'delete-restore',
func: async () => {
close();
await db.trash.restore(note.id);
Navigation.setRoutesToUpdate([
Navigation.routeNames.Tags,
Navigation.routeNames.Notes,
Navigation.routeNames.Notebooks,
Navigation.routeNames.NotesPage,
Navigation.routeNames.Favorites,
Navigation.routeNames.Trash,
]);
type = note.type === 'trash' ? note.itemType : note.type;
ToastEvent.show({
heading:
type === 'note'
? 'Note restored from trash'
: 'Notebook restored from trash',
type: 'success',
});
},
},
{
name: 'Remove',
icon: 'delete',
func: () => {
close('permanant_delete');
},
},
];
const columnItemsData = [
{
name: 'Dark Mode',
icon: 'theme-light-dark',
func: () => {
if (!colors.night) {
MMKV.setStringAsync('theme', JSON.stringify({night: true}));
changeColorScheme(COLOR_SCHEME_DARK);
} else {
MMKV.setStringAsync('theme', JSON.stringify({night: false}));
changeColorScheme(COLOR_SCHEME_LIGHT);
}
},
switch: true,
on: colors.night ? true : false,
close: false,
nopremium: true,
id: notesnook.ids.dialogs.actionsheet.night,
},
{
name: 'Pin',
icon: 'pin',
func: async () => {
if (!note.id) return;
close();
if (note.type === 'note') {
if (db.notes.pinned.length === 3 && !note.pinned) {
ToastEvent.show({
heading: 'Cannot pin more than 3 notes',
type: 'error',
context: 'local',
});
return;
}
await db.notes.note(note.id).pin();
} else {
if (db.notebooks.pinned.length === 3 && !note.pinned) {
ToastEvent.show({
heading: 'Cannot pin more than 3 notebooks',
type: 'error',
context: 'local',
});
return;
}
await db.notebooks.notebook(note.id).pin();
}
localRefresh(item.type);
},
close: false,
check: true,
on: note.pinned,
nopremium: true,
id: notesnook.ids.dialogs.actionsheet.pin,
},
{
name: 'Favorite',
icon: 'star',
func: async () => {
if (!note.id) return;
close();
if (note.type === 'note') {
await db.notes.note(note.id).favorite();
} else {
await db.notebooks.notebook(note.id).favorite();
}
//dispatch({type: Actions.NOTES});
dispatchh({type:Actions.NOTES});
//setNotes()
//eSendEvent("onListUpdate",db.notes.note(note.id).data);
return;
Navigation.setRoutesToUpdate([
Navigation.routeNames.NotesPage,
Navigation.routeNames.Favorites,
Navigation.routeNames.Notes,
]);
localRefresh(item.type, true);
},
close: false,
check: true,
on: note.favorite,
nopremium: true,
id: notesnook.ids.dialogs.actionsheet.favorite,
color: 'orange',
},
{
name: isPinnedToMenu
? 'Remove Shortcut from Menu'
: 'Add Shortcut to Menu',
icon: isPinnedToMenu ? 'link-variant-remove' : 'link-variant',
func: async () => {
close();
try {
if (isPinnedToMenu) {
await db.settings.unpin(note.id);
} 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});
}
}
setIsPinnedToMenu(db.settings.isPinned(note.id));
dispatch({type: Actions.MENU_PINS});
} catch (e) {}
},
close: false,
check: true,
on: isPinnedToMenu,
nopremium: true,
id: notesnook.ids.dialogs.actionsheet.pinMenu,
},
];
const _renderRowItem = rowItem =>
rowItems.includes(rowItem.name) ? (
{rowItem.name}
) : null;
const _renderColumnItem = item =>
(note.id && columnItems.includes(item.name)) ||
(item.name === 'Dark Mode' && columnItems.includes(item.name)) ? (
{
item.func();
}}
style={{
width: '100%',
alignSelf: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-end',
paddingHorizontal: 12,
paddingVertical: pv,
height: 50,
}}>
{item.name}
{item.switch ? (
) : undefined}
{item.check ? (
) : null}
) : null;
const onPressVaultButton = async () => {
if (!note.id) return;
if (note.locked) {
close('unlock');
} else {
db.vault
.add(note.id)
.then(r => {
let n = db.notes.note(note.id).data;
if (n.locked) {
close();
}
Navigation.setRoutesToUpdate([
Navigation.routeNames.NotesPage,
Navigation.routeNames.Favorites,
Navigation.routeNames.Notes,
]);
localRefresh(note.type);
})
.catch(async e => {
switch (e.message) {
case db.vault.ERRORS.noVault:
close('novault');
break;
case db.vault.ERRORS.vaultLocked:
close('locked');
break;
case db.vault.ERRORS.wrongPassword:
close();
break;
}
});
}
};
const onScrollEnd = () => {
getRef().current?.handleChildScrollEnd();
};
return (
{
if (!item.dateDeleted) {
localRefresh(item.type, true);
}
}}
style={{
paddingBottom: 30,
backgroundColor: colors.bg,
paddingHorizontal: 0,
borderBottomRightRadius: DDS.isLargeTablet() ? 10 : 1,
borderBottomLeftRadius: DDS.isLargeTablet() ? 10 : 1,
}}>
{
Keyboard.dismiss();
}}
/>
{!note || !note.id ? (
Start writing to save your note.
) : (
{note?.title.replace('\n', '')}
{note.headline || note.description ? (
{note.type === 'notebook' && note.description
? note.description
: null}
{note.type === 'note' && note.headline
? note.headline[item.headline.length - 1] === '\n'
? note.headline.slice(0, note.headline.length - 1)
: note.headline
: null}
) : null}
{note.type === 'note'
? 'Last edited on ' + timeConverter(note.dateEdited)
: null}
{note.type !== 'note' && !note.dateDeleted
? 'Created on ' + timeConverter(note.dateCreated)
: null}
{note.dateDeleted
? 'Deleted on ' + timeConverter(note.dateDeleted)
: null}
{note.type === 'notebook' && (
{note && note.topics && note.topics.length > 0
? note.topics
.slice()
.sort((a, b) => a.dateEdited - b.dateEdited)
.slice(0, 6)
.map(topic => (
{topic.title.length > 16
? topic.title.slice(0, 16) + '...'
: topic.title}
))
: null}
)}
{note.type !== 'note' || refreshing ? null : (
await Sync.run("local")}
style={{
borderColor: colors.accent,
paddingHorizontal: 5,
borderRadius: 2.5,
justifyContent: 'center',
alignItems: 'center',
marginTop: 5,
borderWidth: 1,
height: 18,
}}>
{user && lastSynced > note.dateEdited ? 'Synced' : 'Sync Now'}
)}
{refreshing ? (
) : null}
)}
{note.id || note.dateCreated ? (
{rowItemsData.map(_renderRowItem)}
) : null}
{note.type === 'note' ? (
{note.locked ? 'Remove from Vault' : 'Add to Vault'}
) : null}
{noteInTopic ? (
{
await db.notebooks
.notebook(editing.actionAfterFirstSave.notebook)
.topics.topic(editing.actionAfterFirstSave.id)
.delete(note.id);
Navigation.setRoutesToUpdate([
Navigation.routeNames.Notebooks,
Navigation.routeNames.Notes,
Navigation.routeNames.NotesPage,
Navigation.routeNames.Notebook,
]);
setNote(db.notes.note(note.id).data);
close();
}}
testID={notesnook.ids.dialogs.actionsheet.vault}
customStyle={{
width: '95%',
alignSelf: 'center',
height: 50,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginTop: 10,
}}>
Remove from Topic
) : null}
{hasColors && note.id ? (
) : null}
{hasTags && note ? (
) : null}
{columnItems.length > 0 ? (
{columnItemsData.map(_renderColumnItem)}
) : null}
{note.type === 'note' && user && lastSynced >= note.dateEdited ? (
This note is encrypted and synced
No one can read it except you.
) : null}
{DDS.isTab ? (
) : null}
);
};