migrate basic editor to tiptap

This commit is contained in:
ammarahm-ed
2022-03-26 16:05:58 +05:00
parent bce5e7ea2d
commit 478d5c02fc
29 changed files with 670 additions and 442 deletions

View File

@@ -4,6 +4,7 @@ import Animated, { Easing } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { notesnook } from '../../../e2e/test.ids';
import { editorState } from '../../screens/editor/tiptap/utils';
import { useSelectionStore, useSettingStore } from '../../stores/stores';
import { editing, getElevation, showTooltip, TOOLTIP_POSITIONS } from '../../utils';
import { normalize, SIZE } from '../../utils/size';
@@ -28,13 +29,13 @@ export const FloatingButton = ({ title, onPress, color = 'accent', shouldShow =
}
const onKeyboardHide = async () => {
editing.keyboardState = false;
editorState().keyboardState = false;
if (deviceMode !== 'mobile') return;
animate(0);
};
const onKeyboardShow = async () => {
editing.keyboardState = true;
editorState().keyboardState = true;
if (deviceMode !== 'mobile') return;
animate(150);
};

View File

@@ -37,6 +37,7 @@ import Heading from '../ui/typography/heading';
import Paragraph from '../ui/typography/paragraph';
import { Walkthrough } from '../walkthroughs';
import NewFeature from '../sheets/new-feature/index';
import { editorState } from '../../screens/editor/tiptap/utils';
const Launcher = React.memo(
() => {
@@ -166,9 +167,9 @@ const Launcher = React.memo(
!appState.movedAway &&
Date.now() < appState.timestamp + 3600000
) {
editing.isRestoringState = true;
editing.currentlyEditing = true;
editing.movedAway = false;
editorState().currentlyEditing = true;
editorState().isRestoringState = true;
editorState().movedAway = false;
if (!DDS.isTab) {
tabBarRef.current?.goToPage(1);
}

View File

@@ -13,6 +13,7 @@ import tiny from '../../screens/editor/tiny/tiny';
import { Button } from '../ui/button';
import Heading from '../ui/typography/heading';
import Paragraph from '../ui/typography/paragraph';
import { editorState } from '../../screens/editor/tiptap/utils';
export const translatePrem = new Animated.Value(-dWidth);
export const opacityPrem = new Animated.Value(0);
@@ -94,7 +95,7 @@ export const PremiumToast = ({ close, context = 'global', offset = 0 }) => {
const onPress = async () => {
open(null);
eSendEvent(eCloseActionSheet);
if (editing.isFocused) {
if (editorState().isFocused) {
tiny.call(EditorWebView, tiny.blur);
}
await sleep(300);

View File

@@ -14,6 +14,7 @@ import { Button } from '../ui/button';
import SheetWrapper from '../ui/sheet';
import Heading from '../ui/typography/heading';
import Paragraph from '../ui/typography/paragraph';
import { editorState } from '../../screens/editor/tiptap/utils';
const SheetProvider = ({ context = 'global' }) => {
const colors = useThemeStore(state => state.colors);
@@ -45,7 +46,7 @@ const SheetProvider = ({ context = 'global' }) => {
setVisible(true);
if (data.editor) {
editor.current.refocus = false;
if (editing.keyboardState) {
if (editorState().keyboardState) {
tiny.call(EditorWebView, tiny.cacheRange + tiny.blur);
editor.current.refocus = true;
}
@@ -59,8 +60,8 @@ const SheetProvider = ({ context = 'global' }) => {
actionSheetRef.current?.setModalVisible(true);
return;
} else {
if (editor.current.refocus) {
editing.isFocused = true;
if (editor.current?.refocus) {
editorState().isFocused = true;
await reFocusEditor();
tiny.call(EditorWebView, tiny.restoreRange + tiny.clearRange);
editor.current.refocus = false;

View File

@@ -2,6 +2,7 @@ import React, { Component, createRef } from 'react';
import { Platform } from 'react-native';
import { Keyboard } from 'react-native';
import { FlatList, TextInput, View } from 'react-native';
import { editorState } from '../../screens/editor/tiptap/utils';
import { DDS } from '../../services/device-detection';
import { editing } from '../../utils';
@@ -34,7 +35,7 @@ export default class Tabs extends Component {
this.hideKeyboardIfVisible();
let cOffset = this.scrollOffset.toFixed(0);
let pOffset = this.props.offsets.b.toFixed(0);
// let heightCheck = !editing.tooltip
// let heightCheck = !editorState().tooltip
// ? this.props.dimensions.height - 70
// : this.props.dimensions.height - 140;
@@ -86,13 +87,13 @@ export default class Tabs extends Component {
hideKeyboardIfVisible(close) {
if (!close && this.nextPage === 1) return;
if (Platform.OS === 'ios') return;
if (editing.movedAway) return;
if (editorState().movedAway) return;
if (
(editing.keyboardState || editing.isFocused) &&
(editorState().keyboardState || editorState().isFocused) &&
this.scrollOffset < this.props.offsets.b - 50
) {
editing.keyboardState = false;
editorState().keyboardState = false;
Keyboard.dismiss();
}
}
@@ -270,7 +271,7 @@ export default class Tabs extends Component {
snapToAlignment="start"
snapToOffsets={[this.props.offsets.a, this.props.offsets.b, this.props.offsets.c]}
contentOffset={{
x: editing.movedAway ? this.props.offsets.a : this.props.offsets.b
x: editorState().movedAway ? this.props.offsets.a : this.props.offsets.b
}}
data={['drawer', 'navigation', 'editor']}
renderItem={this.renderItem}

View File

@@ -8,6 +8,7 @@ import { notesnook } from '../../e2e/test.ids';
import { SideMenu } from '../components/side-menu';
import Tabs from '../components/tabs';
import { EditorWrapper } from '../screens/editor/EditorWrapper';
import { editorState } from '../screens/editor/tiptap/utils';
import { DDS } from '../services/device-detection';
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../services/event-manager';
import { useEditorStore, useSettingStore } from '../stores/stores';
@@ -151,10 +152,10 @@ export const TabsHolder = React.memo(
if (current === 'tablet') {
tabBarRef.current?.goToIndex(0);
} else {
if (!editing.movedAway) {
if (!editorState().movedAway) {
tabBarRef.current?.goToIndex(2);
} else {
console.log('index one', editing.movedAway);
console.log('index one', editorState().movedAway);
tabBarRef.current?.goToIndex(1);
}
}
@@ -316,17 +317,17 @@ let layoutTimer = null;
const onChangeTab = async obj => {
if (obj.i === 1) {
editing.movedAway = false;
editing.isFocused = true;
editorState().movedAway = false;
editorState().isFocused = true;
activateKeepAwake();
if (!editing.currentlyEditing) {
if (!editorState().currentlyEditing) {
eSendEvent(eOnLoadNote, { type: 'new' });
}
} else {
if (obj.from === 1) {
deactivateKeepAwake();
editing.movedAway = true;
editing.isFocused = false;
editorState().movedAway = true;
editorState().isFocused = false;
eSendEvent(eClearEditor, 'removeHandler');
setTimeout(() => useEditorStore.getState().setSearchReplace(false), 1);
let id = useEditorStore.getState().currentEditingNote;

View File

@@ -36,6 +36,7 @@ import tiny, { safeKeyboardDismiss } from './tiny/tiny';
import { endSearch } from './tiny/toolbar/commands';
import { toolbarRef } from './tiny/toolbar/constants';
import picker from './tiny/toolbar/picker';
import { editorState } from './tiptap/utils';
const EditorHeader = ({ editor }) => {
const colors = useThemeStore(state => state.colors);
@@ -59,7 +60,7 @@ const EditorHeader = ({ editor }) => {
return;
}
if (deviceMode === 'mobile') {
editing.movedAway = true;
editorState().movedAway = true;
}
eSendEvent('showTooltip');
toolbarRef.current?.scrollTo({
@@ -83,7 +84,7 @@ const EditorHeader = ({ editor }) => {
setTimeout(() => {
useEditorStore.getState().setCurrentlyEditingNote(null);
}, 1);
editing.currentlyEditing = false;
editorState().currentlyEditing = false;
keyboardListener.current?.remove();
editor?.reset();
}
@@ -122,9 +123,9 @@ const EditorHeader = ({ editor }) => {
});
return;
}
if (editing.isFocused) {
if (editorState().isFocused) {
safeKeyboardDismiss();
editing.isFocused = true;
editorState().isFocused = true;
}
eSendEvent(eOpenPublishNoteDialog, note);
};
@@ -142,9 +143,9 @@ const EditorHeader = ({ editor }) => {
return;
}
if (editing.isFocused || editing.keyboardState) {
if (editorState().isFocused || editorState().keyboardState) {
safeKeyboardDismiss();
editing.isFocused = true;
editorState().isFocused = true;
}
Properties.present(note, ['Dark Mode']);
@@ -208,13 +209,13 @@ const EditorHeader = ({ editor }) => {
handleBack.current = BackHandler.addEventListener('hardwareBackPress', _onHardwareBackPress);
return;
}
if (editing.currentlyEditing) {
if (editorState().currentlyEditing) {
await _onBackPress();
}
};
const _onHardwareBackPress = async () => {
if (editing.currentlyEditing) {
if (editorState().currentlyEditing) {
await _onBackPress();
return true;
}
@@ -280,9 +281,9 @@ const EditorHeader = ({ editor }) => {
}}
top={50}
onPress={async () => {
if (editing.isFocused) {
if (editorState().isFocused) {
safeKeyboardDismiss();
editing.isFocused = true;
editorState().isFocused = true;
}
umami.pageView('/pro-screen', '/editor');
eSendEvent(eOpenPremiumDialog);
@@ -343,7 +344,7 @@ const EditorHeader = ({ editor }) => {
top={50}
onPress={() => {
eSendEvent(eOpenFullscreenEditor);
editing.isFullscreen = true;
editorState().isFullscreen = true;
}}
/>
) : null}

View File

@@ -10,6 +10,7 @@ import { editing } from '../../utils';
import { eOnLoadNote } from '../../utils/events';
import { SIZE } from '../../utils/size';
import { sleep, timeConverter } from '../../utils/time';
import { editorState } from './tiptap/utils';
let timer = null;
let timerError = null;
@@ -21,7 +22,7 @@ const EditorOverlay = () => {
const opacity = useValue(1);
const load = async _loading => {
editing.overlay = true;
editorState().overlay = true;
clearTimeout(timer);
clearTimeout(timerError);
clearTimeout(timerClosing);
@@ -42,7 +43,7 @@ const EditorOverlay = () => {
clearTimeout(timerError);
clearTimeout(timerClosing);
setError(false);
editing.overlay = false;
editorState().overlay = false;
timing(opacity, {
toValue: 0,
duration: 150,

View File

@@ -16,7 +16,7 @@ import { useThemeStore } from '../../stores/theme';
import { editorRef } from '../../utils/global-refs';
import useIsFloatingKeyboard from '../../utils/hooks/use-is-floating-keyboard';
import EditorOverlay from './EditorOverlay';
import { textInput } from './tiptap/utils';
import { editorController, editorState, textInput } from './tiptap/utils';
export const EditorWrapper = ({ width }) => {
const colors = useThemeStore(state => state.colors);
@@ -27,9 +27,9 @@ export const EditorWrapper = ({ width }) => {
const onAppStateChanged = async state => {
if (state === 'active') {
// if (!editing.movedAway) {
// await checkStatus(false);
// }
if (!editorState().movedAway) {
editorController.current.onReady();
}
}
};

View File

@@ -1,13 +1,13 @@
import React, { useEffect, useState } from 'react';
import { Platform, View } from 'react-native';
import { IconButton } from '../../components/ui/icon-button';
import { useThemeStore } from '../../stores/theme';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
import { editing } from '../../utils';
import { SIZE } from '../../utils/size';
import { useThemeStore } from '../../stores/theme';
import useKeyboard from '../../utils/hooks/use-keyboard';
import { SIZE } from '../../utils/size';
import { EditorWebView } from './Functions';
import tiny, { safeKeyboardDismiss } from './tiny/tiny';
import { editorState } from './tiptap/utils';
const HistoryComponent = () => {
const colors = useThemeStore(state => state.colors);
@@ -16,7 +16,7 @@ const HistoryComponent = () => {
redo: false
});
const keyboard = useKeyboard();
editing.keyboardState = keyboard.keyboardShown;
editorState().keyboardState = keyboard.keyboardShown;
const onHistoryChange = data => {
setHistoryState(data);
@@ -47,7 +47,7 @@ const HistoryComponent = () => {
height: 35
}}
onPress={() => {
editing.keyboardState = true;
editorState().keyboardState = true;
safeKeyboardDismiss();
}}
/>

View File

@@ -2,10 +2,11 @@ import React from 'react';
import { Platform, View } from 'react-native';
import WebView from 'react-native-webview';
import { notesnook } from '../../../e2e/test.ids';
import { useEditorStore, useUserStore } from '../../stores/stores';
import { useUserStore } from '../../stores/stores';
import EditorHeader from './EditorHeader';
import { sourceUri, _onShouldStartLoadWithRequest } from './Functions';
import { useEditor } from './tiptap/use-editor';
import { editorController } from './tiptap/utils';
const source = { uri: sourceUri + 'index.html' };
@@ -20,8 +21,8 @@ const style = {
const Editor = React.memo(
() => {
const premiumUser = useUserStore(state => state.premium);
const sessionId = useEditorStore(state => state.sessionId);
const editor = useEditor();
editorController.current = editor;
return editor.loading ? null : (
<>
@@ -43,7 +44,7 @@ const Editor = React.memo(
// onError={() => {
// onResetRequested();
// }}
injectedJavaScript={`globalThis.sessionId="${sessionId}";`}
injectedJavaScript={`globalThis.sessionId="${editor.sessionId}";`}
javaScriptEnabled={true}
focusable={true}
keyboardDisplayRequiresUserAction={false}

View File

@@ -1,7 +1,7 @@
import { Platform } from 'react-native';
import { editing } from '../../../utils';
import { EditorWebView, getWebviewInit, post } from '../Functions';
import { textInput } from '../tiptap/utils';
import { editorState, textInput } from '../tiptap/utils';
/**
*
@@ -206,8 +206,8 @@ function call(webview, func, noqueue) {
}
export function safeKeyboardDismiss() {
console.log('keyboard state', editing.keyboardState);
if (!editing.keyboardState) return;
console.log('keyboard state', editorState().keyboardState);
if (!editorState().keyboardState) return;
if (Platform.OS === 'android') {
textInput.current?.focus();
textInput.current?.blur();
@@ -224,10 +224,10 @@ const redo = `tinymce.activeEditor.undoManager.redo();`;
const clearHistory = `tinymce.activeEditor.undoManager.clear();`;
const onKeyboardShow = () => {
if (!editing.movedAway) {
editing.isFocused = true;
if (!editorState().movedAway) {
editorState().isFocused = true;
if (Platform.OS === 'ios') {
if (editing.focusType === 'title') return;
if (editorState().focusType === 'title') return;
call(EditorWebView, keyboardStateChanged);
}
}

View File

@@ -4,6 +4,7 @@ import { eSendEvent } from '../../../../services/event-manager';
import { editing } from '../../../../utils';
import { sleep } from '../../../../utils/time';
import { EditorWebView, textInput } from '../../Functions';
import { editorState } from '../../tiptap/utils';
import tiny from '../tiny';
export const properties = {
@@ -34,13 +35,13 @@ export async function focusEditor(format, kill = true) {
}
export async function reFocusEditor() {
if (editing.isFocused === true) {
if (editorState().isFocused === true) {
if (Platform.OS === 'android') {
await sleep(300);
textInput.current?.focus();
}
await sleep(300);
if (editing.focusType == 'editor') {
if (editorState().focusType == 'editor') {
focusEditor(null, false);
} else {
Platform.OS === 'android' && EditorWebView.current?.requestFocus();

View File

@@ -32,6 +32,7 @@ import {
import ToolbarItemPin from './itempin';
import ToolbarListFormat from './listformat';
import { Table } from './table';
import { editorState } from '../../tiptap/utils';
const ToolbarItem = ({
format,
@@ -90,7 +91,7 @@ const ToolbarItem = ({
properties.selection = data;
let formats = Object.keys(data);
if (!data['link'] && type === 'tooltip') {
if (editing.tooltip) {
if (editorState().tooltip) {
eSendEvent('showTooltip');
}
}
@@ -203,9 +204,9 @@ const ToolbarItem = ({
const onPress = async event => {
if (premium && !isPro) {
let user = await db.user.getUser();
if (editing.isFocused) {
if (editorState().isFocused) {
safeKeyboardDismiss();
editing.isFocused = true;
editorState().isFocused = true;
}
if (user && !isPro && !user.isEmailConfirmed) {
PremiumService.showVerifyEmailDialog();
@@ -223,15 +224,15 @@ const ToolbarItem = ({
}
if (type === 'settings') {
if (editing.isFocused) {
if (editorState().isFocused) {
safeKeyboardDismiss();
editing.isFocused = true;
editorState().isFocused = true;
}
eSendEvent('openEditorSettings');
return;
}
if (editing.tooltip === format && !formatValue) {
if (editorState().tooltip === format && !formatValue) {
focusEditor(format);
eSendEvent('showTooltip');
@@ -316,7 +317,7 @@ const ToolbarItem = ({
}
focusEditor(format);
editing.tooltip = null;
editorState().tooltip = null;
};
const isdefaultColorFormat = /^(dhilitecolor|dforecolor)$/.test(format);

View File

@@ -14,6 +14,7 @@ import tiny from '../tiny';
import { execCommands } from './commands';
import { focusEditor, formatSelection, INPUT_MODE, properties } from './constants';
import LinkPreview from './linkpreview';
import { editorState } from '../../tiptap/utils';
let inputValue = null;
@@ -30,11 +31,11 @@ const ToolbarLinkInput = ({ format, value, setVisible }) => {
}
inputValue = value;
properties.inputMode = value ? INPUT_MODE.NO_EDIT : INPUT_MODE.EDITING;
editing.tooltip = format;
editorState().tooltip = format;
properties.userBlur = false;
return () => {
properties.inputMode = null;
editing.tooltip = null;
editorState().tooltip = null;
inputValue = null;
};
}, [format]);
@@ -87,7 +88,7 @@ const ToolbarLinkInput = ({ format, value, setVisible }) => {
tiny.call(EditorWebView, tiny.clearRange);
}
editing.tooltip = null;
editorState().tooltip = null;
if (inputValue) {
properties.pauseSelectionChange = true;

View File

@@ -12,6 +12,7 @@ import { db } from '../../../../utils/database';
import { eCloseProgressDialog } from '../../../../utils/events';
import { sleep } from '../../../../utils/time';
import { EditorWebView, getNote } from '../../Functions';
import { editorState } from '../../tiptap/utils';
import tiny, { safeKeyboardDismiss } from '../tiny';
const FILE_SIZE_LIMIT = 500 * 1024 * 1024;
@@ -199,9 +200,9 @@ const gallery = async options => {
const pick = async options => {
if (!PremiumService.get()) {
let user = await db.user.getUser();
if (editing.isFocused) {
if (editorState().isFocused) {
safeKeyboardDismiss();
editing.isFocused = true;
editorState().isFocused = true;
}
if (user && !PremiumService.get() && !user.isEmailConfirmed) {
PremiumService.showVerifyEmailDialog();
@@ -220,9 +221,9 @@ const pick = async options => {
return;
}
if (editing.isFocused) {
if (editorState().isFocused) {
safeKeyboardDismiss();
editing.isFocused = true;
editorState().isFocused = true;
}
presentSheet({

View File

@@ -1,11 +1,11 @@
import React, { useEffect, useState } from 'react';
import { ScrollView, View } from 'react-native';
import { useThemeStore } from '../../../../stores/theme';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../../../services/event-manager';
import { editing } from '../../../../utils';
import { useThemeStore } from '../../../../stores/theme';
import layoutmanager from '../../../../utils/layout-manager';
import { normalize } from '../../../../utils/size';
import { EditorWebView } from '../../Functions';
import { editorState } from '../../tiptap/utils';
import tiny from '../tiny';
import ColorGroup from './colorgroup';
import { properties } from './constants';
@@ -28,7 +28,7 @@ const Tooltip = () => {
const show = async data => {
properties.userBlur = true;
if (!data) {
editing.tooltip = null;
editorState().tooltip = null;
if (group) {
layoutmanager.withAnimation(150);
setGroup(null);
@@ -36,14 +36,14 @@ const Tooltip = () => {
return;
}
if (!data) return;
editing.tooltip = data.title;
editorState().tooltip = data.title;
if (!data.type) {
data.type = data.title;
}
layoutmanager.withSpringAnimation(200);
setGroup(data);
setTimeout(() => {
if (editing.tooltip !== 'link') {
if (editorState().tooltip !== 'link') {
properties.pauseSelectionChange = false;
}
tiny.call(

View File

@@ -1,10 +1,10 @@
import { RefObject } from 'react';
import { createRef, MutableRefObject, RefObject } from 'react';
import { Platform } from 'react-native';
import WebView from 'react-native-webview';
import { sleep } from '../../../utils/time';
import { textInput } from './utils';
function call(webview: RefObject<WebView> | null, func?: string) {
function call(webview: RefObject<WebView | undefined>, func?: string) {
if (!webview || !func) return;
webview.current?.injectJavaScript(func);
}
@@ -14,8 +14,8 @@ const fn = (fn: string) => `(() => {
})();`;
class Commands {
ref: RefObject<WebView> | null = null;
constructor(ref: RefObject<WebView>) {
ref = createRef<WebView | undefined>();
constructor(ref: MutableRefObject<WebView | undefined>) {
this.ref = ref;
}
@@ -50,9 +50,9 @@ statusBar.current.set({date:"",saved:""});
);
};
setSessionId = (id: string) => call(this.ref, fn(`globalThis.sessionId = "${id}"`));
setSessionId = (id: string | null) => call(this.ref, fn(`globalThis.sessionId = "${id}"`));
setStatus = (date: string, saved: string) =>
setStatus = (date: string | undefined, saved: string) =>
call(this.ref, fn(`statusBar.current.set({date:"${date}",saved:"${saved}"})`));
}

View File

@@ -0,0 +1,16 @@
import { useEditor } from './use-editor';
export type useEditorType = ReturnType<typeof useEditor>;
export type EditorState = {
currentlyEditing: boolean;
isFullscreen: boolean;
onNoteCreated: (id: string) => void;
isFocused: boolean;
focusType: 'title' | 'editor' | null;
movedAway: boolean;
tooltip: boolean;
isRestoringState: boolean;
keyboardState: boolean;
ready: boolean;
};

View File

@@ -1,216 +0,0 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../../services/event-manager';
import { useEditorStore } from '../../../stores/stores';
import { editing } from '../../../utils';
import { db } from '../../../utils/database';
import { eOnLoadNote } from '../../../utils/events';
import { timeConverter } from '../../../utils/time';
import Commands from './commands';
import { EditorEvents, isEditorLoaded, makeSessionId, post } from './utils';
export const useEditor = () => {
const [loading, setLoading] = useState(false);
const sessionId = useEditorStore(state => state.sessionId);
const editorRef = useRef();
const currentNote = useRef();
const currentContent = useRef();
const postMessage = async (type, data) => await post(editorRef, type, data);
const timers = useRef({});
const commands = new Commands(editorRef);
const sessionHistoryId = useRef();
useEffect(() => {
console.log('sessionId:', sessionId);
commands.setSessionId(sessionId);
if (sessionId) {
(async () => {
if (!(await isEditorLoaded(editorRef))) {
console.log('should reload');
setLoading(true);
}
})();
}
}, [sessionId, loading]);
useEffect(() => {
if (loading) {
setLoading(false);
}
}, [loading]);
const withTimer = (id, fn, duration) => {
clearTimeout(id);
timers.current[id] = setTimeout(fn, duration);
};
const reset = () => {
currentNote.current = null;
currentContent.current = null;
useEditorStore.getState().setCurrentlyEditingNote(null);
commands.clearContent();
};
async function saveNote(title, id, data, type, sessionId) {
console.log('saving note', id);
try {
if (id && !db.notes.note(id)) {
useEditorStore.getState().setCurrentlyEditingNote(null);
return;
}
let note = id && db.notes.note(id)?.data;
let locked = note?.locked;
if (note?.conflicted) return;
if (!sessionHistoryId.current) {
if (note) {
sessionHistoryId.current = note.dateEdited;
} else {
sessionHistoryId.current = Date.now();
}
}
let noteData = {
id,
sessionId: sessionHistoryId.current
};
if (title) {
noteData.title = title;
}
if (data) {
noteData.content = {
data: data,
type: type
};
}
if (!locked) {
id = await db.notes.add(noteData);
if (!note) currentNote.current = db.notes.note(id).data;
if (useEditorStore.getState().currentEditingNote !== id) {
setTimeout(() => {
useEditorStore.getState().setCurrentlyEditingNote(id);
});
}
} else {
noteData.contentId = note.contentId;
await db.vault.save(noteData);
}
commands.setStatus(timeConverter(db.notes.note(id)?.data?.dateEdited), 'Saved');
return id;
//let n = db.notes.note(id)?.data?.dateEdited;
// tiny.call(EditorWebView, tiny.updateDateEdited(n ? timeConverter(n) : ''));
// tiny.call(EditorWebView, tiny.updateSavingState(!n ? '' : 'Saved'));
} catch (e) {
console.log('error saving: ', e);
}
}
const loadContent = async note => {
currentNote.current = note;
if (note.locked) {
currentContent.current = {
data: note.content.data,
type: note.content.type
};
} else {
let data = await db.content.raw(note.contentId);
if (data) {
data = await db.content.insertPlaceholders(data, 'placeholder.svg');
currentContent.current = {
data: data.data,
type: data.type
};
}
}
};
const loadNote = async item => {
console.log('loading note', item.type);
editing.currentlyEditing = true;
const editorState = useEditorStore.getState();
if (item && item.type === 'new') {
currentNote.current && reset();
editorState.setSessionId(makeSessionId());
commands.focus();
} else {
if (!item.forced && currentNote.current?.id === item.id) return;
currentNote.current && reset();
await loadContent(item);
editorState.setSessionId(makeSessionId(item));
editorState.setCurrentlyEditingNote(item.id);
currentNote.current = item;
commands.setStatus(timeConverter(item.dateEdited), 'Saved');
await postMessage(EditorEvents.title, item.title);
await postMessage(EditorEvents.html, currentContent.current?.data);
}
};
useEffect(() => {
eSubscribeEvent(eOnLoadNote, loadNote);
return () => {
eUnSubscribeEvent(eOnLoadNote, loadNote);
};
}, []);
const onMessage = useCallback(
event => {
let message = event.nativeEvent.data;
message = JSON.parse(message);
console.log(message.type);
if (message.sessionId !== sessionId && message.type !== EditorEvents.status) {
console.log(
'useEditor: message recieved from invalid session',
message.type,
sessionId,
message.sessionId
);
return;
}
switch (message.type) {
case EditorEvents.logger:
console.log(message.type, message.value);
break;
case 'editor-event:content':
saveContent(null, message.value);
break;
case 'editor-event:selection':
break;
case 'editor-event:title':
saveContent(message.value);
break;
}
if (message.type.startsWith('native:')) {
eSendEvent(message.type, message);
}
},
[sessionId]
);
const saveContent = (title, content) => {
currentContent.current = {
data: content,
type: 'tiny'
};
let params = [title, currentNote.current?.id, content, 'tiny', sessionId];
withTimer(currentNote.current?.id, () => saveNote(...params));
};
const onLoad = () => {
console.log('on editor load');
if (currentNote.current) {
console.log('force reload note');
loadNote({ ...currentNote.current, forced: true });
}
};
return { onMessage, ref: editorRef, onLoad, commands, reset, loading, setLoading };
};

View File

@@ -0,0 +1,367 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import WebView from 'react-native-webview';
import { DDS } from '../../../services/device-detection';
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../../services/event-manager';
import { useEditorStore } from '../../../stores/stores';
import { useThemeStore } from '../../../stores/theme';
import { db } from '../../../utils/database';
import { MMKV } from '../../../utils/database/mmkv';
import { eOnLoadNote } from '../../../utils/events';
import { tabBarRef } from '../../../utils/global-refs';
import { timeConverter } from '../../../utils/time';
import Commands from './commands';
import { EditorState } from './types';
import { defaultState, EditorEvents, isEditorLoaded, makeSessionId, post } from './utils';
type Note = {
[name: string]: any;
id: string | null;
type: string;
contentId: string;
title: string;
locked: boolean;
conflicted: boolean;
dateEdited: number;
};
type Content = {
data?: string;
type: string;
};
type SavePayload = {
title?: string;
id?: string | null;
data?: Content['data'];
type?: Content['type'];
sessionId?: string | null;
};
export const useEditor = () => {
const [loading, setLoading] = useState(false);
const [sessionId, setSessionId] = useState<string>(makeSessionId());
const editorRef = useRef<WebView>();
const currentNote = useRef<Note | null>();
const currentContent = useRef<Content | null>();
const timers = useRef<{ [name: string]: NodeJS.Timeout }>({});
const commands = useMemo(() => new Commands(editorRef), []);
const sessionHistoryId = useRef<number>();
const state = useRef<Partial<EditorState>>(defaultState);
console.log('state: ', defaultState);
const postMessage = useCallback(
async (type: string, data: any) => await post(editorRef, type, data),
[]
);
useEffect(() => {
let unsub = useThemeStore.subscribe(state => {
postMessage(EditorEvents.theme, state.colors);
});
return () => {
unsub();
};
}, []);
useEffect(() => {
console.log('sessionId:', sessionId);
commands.setSessionId(sessionId);
if (sessionId) {
(async () => {
if (!state.current?.ready) return;
onReady();
})();
}
}, [sessionId, loading]);
const overlay = (show: boolean, data = { type: 'new' }) => {
eSendEvent('loadingNote', show ? currentNote.current || data : false);
};
const onReady = useCallback(async () => {
if (!(await isEditorLoaded(editorRef))) {
console.log('reload editor');
overlay(true);
setLoading(true);
}
}, []);
useEffect(() => {
if (loading) {
setLoading(false);
}
}, [loading]);
const withTimer = useCallback((id: string, fn: () => void, duration: number) => {
clearTimeout(timers.current[id]);
timers.current[id] = setTimeout(fn, duration);
}, []);
const reset = useCallback(() => {
currentNote.current = null;
currentContent.current = null;
useEditorStore.getState().setCurrentlyEditingNote(null);
commands.clearContent();
}, []);
const saveNote = useCallback(
async ({ title, id, data, type, sessionId: currentSessionId }: SavePayload) => {
console.log('saving note', id);
try {
if (id && !db.notes?.note(id)) {
useEditorStore.getState().setCurrentlyEditingNote(null);
reset();
return;
}
let note = id ? (db.notes?.note(id)?.data as Note) : null;
let locked = note?.locked;
if (note?.conflicted) return;
if (!sessionHistoryId.current) {
if (note) {
sessionHistoryId.current = note.dateEdited;
} else {
sessionHistoryId.current = Date.now();
}
}
let noteData: Partial<Note> = {
id,
sessionId: sessionHistoryId.current
};
if (title) {
noteData.title = title;
}
if (data) {
noteData.content = {
data: data,
type: type
};
}
if (!locked) {
id = await db.notes?.add(noteData);
if (!note && id) {
currentNote.current = db.notes?.note(id).data as Note;
state.current?.onNoteCreated && state.current.onNoteCreated(id);
}
if (useEditorStore.getState().currentEditingNote !== id) {
setTimeout(() => {
id && useEditorStore.getState().setCurrentlyEditingNote(id);
});
}
} else {
//@ts-ignore
noteData.contentId = note.contentId;
//@ts-ignore
await db.vault?.save(noteData);
}
if (id && sessionId === currentSessionId) {
note = db.notes?.note(id)?.data as Note;
commands.setStatus(timeConverter(note.dateEdited), 'Saved');
}
return id;
} catch (e) {
console.log('error saving: ', e);
}
},
[commands, reset]
);
const loadContent = useCallback(async (note: Note) => {
currentNote.current = note;
if (note.locked) {
currentContent.current = {
data: note.content.data,
type: note.content.type
};
} else {
let data = await db.content?.raw(note.contentId);
if (data) {
data = await db.content?.insertPlaceholders(data, 'placeholder.svg');
currentContent.current = {
data: data.data,
type: data.type
};
}
}
}, []);
const loadNote = useCallback(
async (item: Note) => {
console.log('loading note', item.type);
state.current.currentlyEditing = true;
const editorState = useEditorStore.getState();
if (item && item.type === 'new') {
currentNote.current && reset();
setSessionId(makeSessionId());
commands.focus();
} else {
if (!item.forced && currentNote.current?.id === item.id) return;
overlay(true, item);
currentNote.current && reset();
await loadContent(item);
setSessionId(makeSessionId(item));
editorState.setCurrentlyEditingNote(item.id);
currentNote.current = item;
commands.setStatus(timeConverter(item.dateEdited), 'Saved');
await postMessage(EditorEvents.title, item.title);
await postMessage(EditorEvents.html, currentContent.current?.data);
overlay(false);
}
},
[setSessionId]
);
useEffect(() => {
eSubscribeEvent(eOnLoadNote, loadNote);
return () => {
eUnSubscribeEvent(eOnLoadNote, loadNote);
};
}, []);
const onMessage = useCallback(
event => {
let message = event.nativeEvent.data;
message = JSON.parse(message);
console.log(message.type);
if (message.sessionId !== sessionId && message.type !== EditorEvents.status) {
console.log(
'useEditor: message recieved from invalid session',
message.type,
sessionId,
message.sessionId
);
return;
}
switch (message.type) {
case EditorEvents.logger:
console.log(message.type, message.value);
break;
case 'editor-event:content':
saveContent({
type: message.type,
content: message.value
});
break;
case 'editor-event:selection':
break;
case 'editor-event:title':
saveContent({
type: message.type,
title: message.value
});
break;
}
if (message.type.startsWith('native:')) {
eSendEvent(message.type, message);
}
},
[sessionId]
);
const saveContent = useCallback(
({ title, content, type }: { title?: string; content?: string; type: string }) => {
if (type === EditorEvents.content) {
currentContent.current = {
data: content,
type: 'tiny'
};
}
let params = {
title,
data: content,
type: 'tiptap',
sessionId,
id: currentNote.current?.id
};
withTimer(
currentNote.current?.id || 'newnote',
() => {
if (currentNote.current && !params.id) {
params.id = currentNote.current?.id;
}
saveNote(params);
},
300
);
},
[]
);
const onLoad = useCallback(() => {
console.log('on editor load');
state.current.ready = true;
onReady();
postMessage(EditorEvents.theme, useThemeStore.getState().colors);
if (currentNote.current) {
console.log('force reload note');
loadNote({ ...currentNote.current, forced: true });
} else {
restoreEditorState();
}
}, [state, currentNote, loadNote]);
async function restoreEditorState() {
let appState = await MMKV.getItem('appState');
if (appState) {
appState = JSON.parse(appState);
if (
//@ts-ignore
appState.editing &&
//@ts-ignore
appState.note &&
//@ts-ignore
!appState.note.locked &&
//@ts-ignore
appState.note.id &&
//@ts-ignore
Date.now() < appState.timestamp + 3600000
) {
state.current.isRestoringState = true;
//@ts-ignore
overlay(true, appState.note);
state.current.currentlyEditing = true;
if (!DDS.isTab) {
tabBarRef.current?.goToPage(1);
}
setTimeout(() => {
//@ts-ignore
loadNote(appState.note);
}, 1);
MMKV.removeItem('appState');
state.current.movedAway = false;
eSendEvent('load_overlay', 'hide_editor');
state.current.isRestoringState = false;
return;
}
state.current.isRestoringState = false;
return;
}
state.current.isRestoringState = false;
}
return {
onMessage,
ref: editorRef,
onLoad,
commands,
reset,
loading,
setLoading,
state,
sessionId,
setSessionId,
note: currentNote,
onReady
};
};

View File

@@ -1,60 +0,0 @@
import { createRef } from 'react';
import { Platform } from 'react-native';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../../services/event-manager';
import { useEditorStore } from '../../../stores/stores';
import { sleep } from '../../../utils/time';
import commands from './commands';
export const textInput = createRef();
export const EditorEvents = {
html: 'native:html',
title: 'native:title',
theme: 'native:theme',
titleplaceholder: 'native:titleplaceholder',
logger: 'native:logger',
status: 'native:status'
};
function randId(prefix) {
return Math.random()
.toString(36)
.replace('0.', prefix || '');
}
export function makeSessionId(item) {
return item?.id ? item.id + randId('_session_') : randId('session_');
}
export async function isEditorLoaded(ref) {
return await post(ref, EditorEvents.status);
}
export async function post(ref, type, value = null) {
let sessionId = useEditorStore.getState().sessionId;
if (!sessionId) {
console.warn('post called without sessionId of type:', type);
return;
}
let message = {
type,
value,
sessionId: sessionId
};
ref.current?.postMessage(JSON.stringify(message));
let response = await getResponse(type);
console.log('post: ', type, 'result:', response);
return response;
}
const getResponse = async type => {
return new Promise(resolve => {
let callback = data => {
eUnSubscribeEvent(type, callback);
resolve(data);
};
eSubscribeEvent(type, callback);
setTimeout(() => {
resolve(false);
}, 5000);
});
};

View File

@@ -0,0 +1,78 @@
import { createRef, MutableRefObject } from 'react';
import { TextInput } from 'react-native';
import WebView from 'react-native-webview';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../../services/event-manager';
import { useEditorType } from './types';
export const textInput = createRef<TextInput>();
export const editorController = createRef<useEditorType>();
export const defaultState = {
movedAway: true
};
export function editorState() {
if (!editorController.current?.state.current) {
console.warn('Editor state not ready');
}
return editorController.current?.state.current || defaultState;
}
export const EditorEvents: { [name: string]: string } = {
html: 'native:html',
title: 'native:title',
theme: 'native:theme',
titleplaceholder: 'native:titleplaceholder',
logger: 'native:logger',
status: 'native:status'
};
function randId(prefix: string) {
return Math.random()
.toString(36)
.replace('0.', prefix || '');
}
export function makeSessionId(item?: any) {
return item?.id ? item.id + randId('_session_') : randId('session_');
}
export async function isEditorLoaded(ref: MutableRefObject<WebView | undefined>) {
return await post(ref, EditorEvents.status);
}
export async function post(ref: MutableRefObject<WebView | undefined>, type: string, value = null) {
let sessionId = editorController.current?.sessionId;
if (!sessionId) {
console.warn('post called without sessionId of type:', type);
return;
}
let message = {
type,
value,
sessionId: sessionId
};
ref.current?.postMessage(JSON.stringify(message));
let response = await getResponse(type);
console.log('post: ', type, sessionId, 'result:', !!response);
return response;
}
type WebviewResponseData = {
[name: string]: any;
sessionId: string | null;
type: string;
value: any;
};
const getResponse = async (type: string): Promise<WebviewResponseData | false> => {
return new Promise(resolve => {
let callback = (data: WebviewResponseData) => {
eUnSubscribeEvent(type, callback);
resolve(data);
};
eSubscribeEvent(type, callback);
setTimeout(() => {
resolve(false);
}, 5000);
});
};

View File

@@ -9,11 +9,12 @@ import { eSendEvent } from '../../services/event-manager';
import Navigation from '../../services/navigation';
import SearchService from '../../services/search';
import { useNoteStore } from '../../stores/stores';
import { editing, InteractionManager } from '../../utils';
import { InteractionManager } from '../../utils';
import { db } from '../../utils/database';
import { eOnLoadNote } from '../../utils/events';
import { tabBarRef } from '../../utils/global-refs';
import { getNote } from '../editor/Functions';
import { editorState } from '../editor/tiptap/utils';
export const Home = ({ navigation }) => {
const notes = useNoteStore(state => state.notes);
@@ -83,8 +84,8 @@ export const Home = ({ navigation }) => {
if (!DDS.isTab) {
if (getNote()) {
eSendEvent(eOnLoadNote, { type: 'new' });
editing.currentlyEditing = true;
editing.movedAway = false;
editorState().currentlyEditing = true;
editorState().movedAway = false;
}
tabBarRef.current?.goToPage(1);
} else {

View File

@@ -1,23 +1,24 @@
import { groupArray } from 'notes-core/utils/grouping';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { FloatingButton } from '../../components/container/floating-button';
import { ContainerHeader } from '../../components/container/containerheader';
import { FloatingButton } from '../../components/container/floating-button';
import { Header } from '../../components/header';
import { MoveNotes } from '../../components/sheets/move-notes/movenote';
import SelectionHeader from '../../components/selection-header';
import List from '../../components/list';
import { useThemeStore } from '../../stores/theme';
import { useNoteStore } from '../../stores/stores';
import SelectionHeader from '../../components/selection-header';
import { MoveNotes } from '../../components/sheets/move-notes/movenote';
import { DDS } from '../../services/device-detection';
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
import Navigation from '../../services/navigation';
import SearchService from '../../services/search';
import { editing, InteractionManager } from '../../utils';
import { useMenuStore, useNoteStore } from '../../stores/stores';
import { useThemeStore } from '../../stores/theme';
import { InteractionManager } from '../../utils';
import { db } from '../../utils/database';
import { eOnLoadNote, eOpenAddTopicDialog, refreshNotesPage } from '../../utils/events';
import { openLinkInBrowser } from '../../utils/functions';
import { tabBarRef } from '../../utils/global-refs';
import { getNote } from '../editor/Functions';
import { editorState } from '../editor/tiptap/utils';
const getNotes = (params, group = true) => {
if (!params) return [];
@@ -46,6 +47,44 @@ function getAlias(params) {
return alias || '';
}
async function onNoteCreated(id, params) {
if (!params.current || !id) return;
switch (params.current.type) {
case 'topic': {
await db.notes.move(
{
topic: params.current.id,
id: params.current.notebook
},
id
);
editorState().onNoteCreated = null;
Navigation.setRoutesToUpdate([
Navigation.routeNames.Notebooks,
Navigation.routeNames.NotesPage,
Navigation.routeNames.Notebook
]);
break;
}
case 'tag': {
await db.notes.note(id).tag(params.current.id);
editorState().onNoteCreated = null;
Navigation.setRoutesToUpdate([Navigation.routeNames.Tags, Navigation.routeNames.NotesPage]);
break;
}
case 'color': {
await db.notes.note(id).color(params.current.id);
editorState().onNoteCreated = null;
Navigation.setRoutesToUpdate([Navigation.routeNames.NotesPage]);
useMenuStore.getState().setColorNotes();
break;
}
default: {
break;
}
}
}
export const Notes = ({ route, navigation }) => {
const colors = useThemeStore(state => state.colors);
const params = useRef(route?.params);
@@ -70,19 +109,13 @@ export const Notes = ({ route, navigation }) => {
eSubscribeEvent(refreshNotesPage, init);
return () => {
eUnSubscribeEvent(refreshNotesPage, init);
editing.actionAfterFirstSave = {
type: null
};
editorState().onNoteCreated = null;
};
}, []);
const setActionAfterFirstSave = () => {
if (params.current?.get === 'monographs') return;
editing.actionAfterFirstSave = {
type: params.current?.type,
id: params.current?.id,
notebook: params.current?.notebookId
};
editorState().onNoteCreated = id => onNoteCreated(id, params);
};
const init = data => {
@@ -110,18 +143,14 @@ export const Notes = ({ route, navigation }) => {
InteractionManager.runAfterInteractions(() => {
setNotes([]);
}, 150);
editing.actionAfterFirstSave = {
type: null
};
editorState().onNoteCreated = null;
}, []);
useEffect(() => {
navigation.addListener('focus', onFocus);
navigation.addListener('blur', onBlur);
return () => {
editing.actionAfterFirstSave = {
type: null
};
editorState().onNoteCreated = null;
navigation.removeListener('focus', onFocus);
navigation.removeListener('blur', onBlur);
};
@@ -162,8 +191,8 @@ export const Notes = ({ route, navigation }) => {
if (!DDS.isTab) {
if (getNote()) {
eSendEvent(eOnLoadNote, { type: 'new' });
editing.currentlyEditing = true;
editing.movedAway = false;
editorState().currentlyEditing = true;
editorState().movedAway = false;
}
tabBarRef.current?.goToPage(1);
} else {

View File

@@ -12,6 +12,7 @@ import { useNoteStore } from '../stores/stores';
import { DDS } from './device-detection';
import { eSendEvent } from './event-manager';
import SettingsService from './settings';
import { editorState } from '../screens/editor/tiptap/utils';
const NOTIFICATION_TAG = 'notesnook';
const CHANNEL_ID = 'com.streetwriters.notesnook';
@@ -36,7 +37,7 @@ function init() {
if (Platform.OS === 'ios') return;
PushNotification.configure({
onNotification: async function (notification) {
editing.movedAway = false;
editorState().movedAway = false;
MMKV.removeItem('appState');
if (useNoteStore?.getState()?.loading === false) {
//@ts-ignore

View File

@@ -3,16 +3,15 @@ import { groupArray } from 'notes-core/utils/grouping';
import { Dimensions, Platform } from 'react-native';
import create from 'zustand';
import { APP_VERSION } from '../../version';
import { endSearch } from '../screens/editor/tiny/toolbar/commands';
import { eSubscribeEvent, eUnSubscribeEvent } from '../services/event-manager';
import PremiumService from '../services/premium';
import { history } from '../utils';
import { ACCENT } from '../utils/color-scheme';
import { SUBSCRIPTION_STATUS } from '../utils/constants';
import { db } from '../utils/database';
import { MMKV } from '../utils/database/mmkv';
import layoutmanager from '../utils/layout-manager';
import { EditorWebView } from '../screens/editor/Functions';
import tiny from '../screens/editor/tiny/tiny';
import { endSearch } from '../screens/editor/tiny/toolbar/commands';
import {
Announcement,
EditorStore,
@@ -28,7 +27,6 @@ import {
TrashStore,
UserStore
} from './interfaces';
import { ACCENT } from '../utils/color-scheme';
export const useNoteStore = create<NoteStore>((set, get) => ({
notes: [],
@@ -185,18 +183,18 @@ export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
let _p = get().progress;
if (!_p) return;
_p[hash] = null;
tiny.call(
EditorWebView,
`
(function() {
let progress = ${JSON.stringify({
loaded: 1,
total: 1,
hash
})}
tinymce.activeEditor._updateAttachmentProgress(progress);
})()`
);
// tiny.call(
// EditorWebView,
// `
// (function() {
// let progress = ${JSON.stringify({
// loaded: 1,
// total: 1,
// hash
// })}
// tinymce.activeEditor._updateAttachmentProgress(progress);
// })()`
// );
set({ progress: { ..._p } });
},
setProgress: (sent, total, hash, recieved, type) => {
@@ -204,14 +202,14 @@ export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
if (!_p) return;
_p[hash] = { sent, total, hash, recieved, type };
let progress = { total, hash, loaded: type === 'download' ? recieved : sent };
tiny.call(
EditorWebView,
`
(function() {
let progress = ${JSON.stringify(progress)}
tinymce.activeEditor._updateAttachmentProgress(progress);
})()`
);
// tiny.call(
// EditorWebView,
// `
// (function() {
// let progress = ${JSON.stringify(progress)}
// tinymce.activeEditor._updateAttachmentProgress(progress);
// })()`
// );
set({ progress: { ..._p } });
},
encryptionProgress: 0,
@@ -321,14 +319,14 @@ export const useEditorStore = create<EditorStore>((set, get) => ({
set({ searchSelection: value, searchReplace: true });
};
eSubscribeEvent('selectionvalue', func);
tiny.call(
EditorWebView,
`(function() {
if (editor) {
reactNativeEventHandler('selectionvalue',editor.selection.getContent());
}
})();`
);
// tiny.call(
// EditorWebView,
// `(function() {
// if (editor) {
// reactNativeEventHandler('selectionvalue',editor.selection.getContent());
// }
// })();`
// );
}
}));

View File

@@ -13,13 +13,7 @@ import * as RNIap from 'react-native-iap';
import { enabled } from 'react-native-privacy-snapshot';
import { doInBackground, editing } from '..';
import { Walkthrough } from '../../components/walkthroughs';
import {
EditorWebView,
getNote,
getWebviewInit,
updateNoteInEditor
} from '../../screens/editor/Functions';
import tiny from '../../screens/editor/tiny/tiny';
import { editorState } from '../../screens/editor/tiptap/utils';
import Backup from '../../services/backup';
import BiometricService from '../../services/biometrics';
import {
@@ -42,6 +36,7 @@ import {
clearAllStores,
initialize,
useAttachmentStore,
useEditorStore,
useMessageStore,
useNoteStore,
useSettingStore,
@@ -73,15 +68,15 @@ export const useAppEvents = () => {
const onMediaDownloaded = ({ hash, groupId, src }) => {
if (groupId?.startsWith('monograph')) return;
tiny.call(
EditorWebView,
`
(function(){
let image = ${JSON.stringify({ hash, src })};
tinymce.activeEditor._replaceImage(image);
})();
`
);
// tiny.call(
// EditorWebView,
// `
// (function(){
// let image = ${JSON.stringify({ hash, src })};
// tinymce.activeEditor._replaceImage(image);
// })();
// `
// );
};
const onLoadingAttachmentProgress = data => {
@@ -170,8 +165,10 @@ export const useAppEvents = () => {
initialize();
setLastSynced(await db.lastSynced());
setSyncing(false);
if (getNote()) {
await updateNoteInEditor();
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
if (note) {
//await updateNoteInEditor();
}
};
@@ -407,9 +404,7 @@ export const useAppEvents = () => {
await reconnectSSE();
await checkIntentState();
if (getWebviewInit()) {
await MMKV.removeItem('appState');
}
let user = await db.user.getUser();
if (user && !user.isEmailConfirmed) {
try {
@@ -421,7 +416,9 @@ export const useAppEvents = () => {
}
} else {
refValues.current.prevState = 'background';
if (getNote()?.locked && SettingsService.get().appLockMode === 'background') {
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
if (note?.locked && SettingsService.get().appLockMode === 'background') {
eSendEvent(eClearEditor);
}
await storeAppState();
@@ -462,12 +459,14 @@ export const useAppEvents = () => {
}
async function storeAppState() {
if (editing.currentlyEditing) {
if (getNote()?.locked) return;
if (editorState().currentlyEditing) {
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
if (note?.locked) return;
let state = JSON.stringify({
editing: editing.currentlyEditing,
note: getNote(),
movedAway: editing.movedAway,
editing: editorState().currentlyEditing,
note: note,
movedAway: editorState().movedAway,
timestamp: Date.now()
});
await MMKV.setItem('appState', state);
@@ -490,7 +489,9 @@ export const useAppEvents = () => {
eSendEvent(refreshNotesPage);
}
if (notesAddedFromIntent || shareExtensionOpened) {
eSendEvent('loadingNote', getNote());
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
eSendEvent('loadingNote', note);
eSendEvent('webviewreset', true);
MMKV.removeItem('shareExtensionOpened');
}

View File

@@ -34,7 +34,7 @@ export function timeSince(date: number) {
return Math.floor(seconds) < 0 ? '0s ago' : Math.floor(seconds) + 's ago';
}
export const timeConverter = (timestamp: number) => {
export const timeConverter = (timestamp: number | undefined | null) => {
if (!timestamp) return;
let d = new Date(timestamp), // Convert the passed timestamp to milliseconds
yyyy = d.getFullYear(),