mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 06:59:31 +01:00
migrate basic editor to tiptap
This commit is contained in:
@@ -4,6 +4,7 @@ import Animated, { Easing } from 'react-native-reanimated';
|
|||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import { notesnook } from '../../../e2e/test.ids';
|
import { notesnook } from '../../../e2e/test.ids';
|
||||||
|
import { editorState } from '../../screens/editor/tiptap/utils';
|
||||||
import { useSelectionStore, useSettingStore } from '../../stores/stores';
|
import { useSelectionStore, useSettingStore } from '../../stores/stores';
|
||||||
import { editing, getElevation, showTooltip, TOOLTIP_POSITIONS } from '../../utils';
|
import { editing, getElevation, showTooltip, TOOLTIP_POSITIONS } from '../../utils';
|
||||||
import { normalize, SIZE } from '../../utils/size';
|
import { normalize, SIZE } from '../../utils/size';
|
||||||
@@ -28,13 +29,13 @@ export const FloatingButton = ({ title, onPress, color = 'accent', shouldShow =
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onKeyboardHide = async () => {
|
const onKeyboardHide = async () => {
|
||||||
editing.keyboardState = false;
|
editorState().keyboardState = false;
|
||||||
if (deviceMode !== 'mobile') return;
|
if (deviceMode !== 'mobile') return;
|
||||||
animate(0);
|
animate(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyboardShow = async () => {
|
const onKeyboardShow = async () => {
|
||||||
editing.keyboardState = true;
|
editorState().keyboardState = true;
|
||||||
if (deviceMode !== 'mobile') return;
|
if (deviceMode !== 'mobile') return;
|
||||||
animate(150);
|
animate(150);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import Heading from '../ui/typography/heading';
|
|||||||
import Paragraph from '../ui/typography/paragraph';
|
import Paragraph from '../ui/typography/paragraph';
|
||||||
import { Walkthrough } from '../walkthroughs';
|
import { Walkthrough } from '../walkthroughs';
|
||||||
import NewFeature from '../sheets/new-feature/index';
|
import NewFeature from '../sheets/new-feature/index';
|
||||||
|
import { editorState } from '../../screens/editor/tiptap/utils';
|
||||||
|
|
||||||
const Launcher = React.memo(
|
const Launcher = React.memo(
|
||||||
() => {
|
() => {
|
||||||
@@ -166,9 +167,9 @@ const Launcher = React.memo(
|
|||||||
!appState.movedAway &&
|
!appState.movedAway &&
|
||||||
Date.now() < appState.timestamp + 3600000
|
Date.now() < appState.timestamp + 3600000
|
||||||
) {
|
) {
|
||||||
editing.isRestoringState = true;
|
editorState().currentlyEditing = true;
|
||||||
editing.currentlyEditing = true;
|
editorState().isRestoringState = true;
|
||||||
editing.movedAway = false;
|
editorState().movedAway = false;
|
||||||
if (!DDS.isTab) {
|
if (!DDS.isTab) {
|
||||||
tabBarRef.current?.goToPage(1);
|
tabBarRef.current?.goToPage(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import tiny from '../../screens/editor/tiny/tiny';
|
|||||||
import { Button } from '../ui/button';
|
import { Button } from '../ui/button';
|
||||||
import Heading from '../ui/typography/heading';
|
import Heading from '../ui/typography/heading';
|
||||||
import Paragraph from '../ui/typography/paragraph';
|
import Paragraph from '../ui/typography/paragraph';
|
||||||
|
import { editorState } from '../../screens/editor/tiptap/utils';
|
||||||
|
|
||||||
export const translatePrem = new Animated.Value(-dWidth);
|
export const translatePrem = new Animated.Value(-dWidth);
|
||||||
export const opacityPrem = new Animated.Value(0);
|
export const opacityPrem = new Animated.Value(0);
|
||||||
@@ -94,7 +95,7 @@ export const PremiumToast = ({ close, context = 'global', offset = 0 }) => {
|
|||||||
const onPress = async () => {
|
const onPress = async () => {
|
||||||
open(null);
|
open(null);
|
||||||
eSendEvent(eCloseActionSheet);
|
eSendEvent(eCloseActionSheet);
|
||||||
if (editing.isFocused) {
|
if (editorState().isFocused) {
|
||||||
tiny.call(EditorWebView, tiny.blur);
|
tiny.call(EditorWebView, tiny.blur);
|
||||||
}
|
}
|
||||||
await sleep(300);
|
await sleep(300);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { Button } from '../ui/button';
|
|||||||
import SheetWrapper from '../ui/sheet';
|
import SheetWrapper from '../ui/sheet';
|
||||||
import Heading from '../ui/typography/heading';
|
import Heading from '../ui/typography/heading';
|
||||||
import Paragraph from '../ui/typography/paragraph';
|
import Paragraph from '../ui/typography/paragraph';
|
||||||
|
import { editorState } from '../../screens/editor/tiptap/utils';
|
||||||
|
|
||||||
const SheetProvider = ({ context = 'global' }) => {
|
const SheetProvider = ({ context = 'global' }) => {
|
||||||
const colors = useThemeStore(state => state.colors);
|
const colors = useThemeStore(state => state.colors);
|
||||||
@@ -45,7 +46,7 @@ const SheetProvider = ({ context = 'global' }) => {
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
if (data.editor) {
|
if (data.editor) {
|
||||||
editor.current.refocus = false;
|
editor.current.refocus = false;
|
||||||
if (editing.keyboardState) {
|
if (editorState().keyboardState) {
|
||||||
tiny.call(EditorWebView, tiny.cacheRange + tiny.blur);
|
tiny.call(EditorWebView, tiny.cacheRange + tiny.blur);
|
||||||
editor.current.refocus = true;
|
editor.current.refocus = true;
|
||||||
}
|
}
|
||||||
@@ -59,8 +60,8 @@ const SheetProvider = ({ context = 'global' }) => {
|
|||||||
actionSheetRef.current?.setModalVisible(true);
|
actionSheetRef.current?.setModalVisible(true);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (editor.current.refocus) {
|
if (editor.current?.refocus) {
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
await reFocusEditor();
|
await reFocusEditor();
|
||||||
tiny.call(EditorWebView, tiny.restoreRange + tiny.clearRange);
|
tiny.call(EditorWebView, tiny.restoreRange + tiny.clearRange);
|
||||||
editor.current.refocus = false;
|
editor.current.refocus = false;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { Component, createRef } from 'react';
|
|||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import { Keyboard } from 'react-native';
|
import { Keyboard } from 'react-native';
|
||||||
import { FlatList, TextInput, View } from 'react-native';
|
import { FlatList, TextInput, View } from 'react-native';
|
||||||
|
import { editorState } from '../../screens/editor/tiptap/utils';
|
||||||
import { DDS } from '../../services/device-detection';
|
import { DDS } from '../../services/device-detection';
|
||||||
import { editing } from '../../utils';
|
import { editing } from '../../utils';
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ export default class Tabs extends Component {
|
|||||||
this.hideKeyboardIfVisible();
|
this.hideKeyboardIfVisible();
|
||||||
let cOffset = this.scrollOffset.toFixed(0);
|
let cOffset = this.scrollOffset.toFixed(0);
|
||||||
let pOffset = this.props.offsets.b.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 - 70
|
||||||
// : this.props.dimensions.height - 140;
|
// : this.props.dimensions.height - 140;
|
||||||
|
|
||||||
@@ -86,13 +87,13 @@ export default class Tabs extends Component {
|
|||||||
hideKeyboardIfVisible(close) {
|
hideKeyboardIfVisible(close) {
|
||||||
if (!close && this.nextPage === 1) return;
|
if (!close && this.nextPage === 1) return;
|
||||||
if (Platform.OS === 'ios') return;
|
if (Platform.OS === 'ios') return;
|
||||||
if (editing.movedAway) return;
|
if (editorState().movedAway) return;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(editing.keyboardState || editing.isFocused) &&
|
(editorState().keyboardState || editorState().isFocused) &&
|
||||||
this.scrollOffset < this.props.offsets.b - 50
|
this.scrollOffset < this.props.offsets.b - 50
|
||||||
) {
|
) {
|
||||||
editing.keyboardState = false;
|
editorState().keyboardState = false;
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,7 +271,7 @@ export default class Tabs extends Component {
|
|||||||
snapToAlignment="start"
|
snapToAlignment="start"
|
||||||
snapToOffsets={[this.props.offsets.a, this.props.offsets.b, this.props.offsets.c]}
|
snapToOffsets={[this.props.offsets.a, this.props.offsets.b, this.props.offsets.c]}
|
||||||
contentOffset={{
|
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']}
|
data={['drawer', 'navigation', 'editor']}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { notesnook } from '../../e2e/test.ids';
|
|||||||
import { SideMenu } from '../components/side-menu';
|
import { SideMenu } from '../components/side-menu';
|
||||||
import Tabs from '../components/tabs';
|
import Tabs from '../components/tabs';
|
||||||
import { EditorWrapper } from '../screens/editor/EditorWrapper';
|
import { EditorWrapper } from '../screens/editor/EditorWrapper';
|
||||||
|
import { editorState } from '../screens/editor/tiptap/utils';
|
||||||
import { DDS } from '../services/device-detection';
|
import { DDS } from '../services/device-detection';
|
||||||
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../services/event-manager';
|
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../services/event-manager';
|
||||||
import { useEditorStore, useSettingStore } from '../stores/stores';
|
import { useEditorStore, useSettingStore } from '../stores/stores';
|
||||||
@@ -151,10 +152,10 @@ export const TabsHolder = React.memo(
|
|||||||
if (current === 'tablet') {
|
if (current === 'tablet') {
|
||||||
tabBarRef.current?.goToIndex(0);
|
tabBarRef.current?.goToIndex(0);
|
||||||
} else {
|
} else {
|
||||||
if (!editing.movedAway) {
|
if (!editorState().movedAway) {
|
||||||
tabBarRef.current?.goToIndex(2);
|
tabBarRef.current?.goToIndex(2);
|
||||||
} else {
|
} else {
|
||||||
console.log('index one', editing.movedAway);
|
console.log('index one', editorState().movedAway);
|
||||||
tabBarRef.current?.goToIndex(1);
|
tabBarRef.current?.goToIndex(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,17 +317,17 @@ let layoutTimer = null;
|
|||||||
|
|
||||||
const onChangeTab = async obj => {
|
const onChangeTab = async obj => {
|
||||||
if (obj.i === 1) {
|
if (obj.i === 1) {
|
||||||
editing.movedAway = false;
|
editorState().movedAway = false;
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
activateKeepAwake();
|
activateKeepAwake();
|
||||||
if (!editing.currentlyEditing) {
|
if (!editorState().currentlyEditing) {
|
||||||
eSendEvent(eOnLoadNote, { type: 'new' });
|
eSendEvent(eOnLoadNote, { type: 'new' });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (obj.from === 1) {
|
if (obj.from === 1) {
|
||||||
deactivateKeepAwake();
|
deactivateKeepAwake();
|
||||||
editing.movedAway = true;
|
editorState().movedAway = true;
|
||||||
editing.isFocused = false;
|
editorState().isFocused = false;
|
||||||
eSendEvent(eClearEditor, 'removeHandler');
|
eSendEvent(eClearEditor, 'removeHandler');
|
||||||
setTimeout(() => useEditorStore.getState().setSearchReplace(false), 1);
|
setTimeout(() => useEditorStore.getState().setSearchReplace(false), 1);
|
||||||
let id = useEditorStore.getState().currentEditingNote;
|
let id = useEditorStore.getState().currentEditingNote;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import tiny, { safeKeyboardDismiss } from './tiny/tiny';
|
|||||||
import { endSearch } from './tiny/toolbar/commands';
|
import { endSearch } from './tiny/toolbar/commands';
|
||||||
import { toolbarRef } from './tiny/toolbar/constants';
|
import { toolbarRef } from './tiny/toolbar/constants';
|
||||||
import picker from './tiny/toolbar/picker';
|
import picker from './tiny/toolbar/picker';
|
||||||
|
import { editorState } from './tiptap/utils';
|
||||||
|
|
||||||
const EditorHeader = ({ editor }) => {
|
const EditorHeader = ({ editor }) => {
|
||||||
const colors = useThemeStore(state => state.colors);
|
const colors = useThemeStore(state => state.colors);
|
||||||
@@ -59,7 +60,7 @@ const EditorHeader = ({ editor }) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (deviceMode === 'mobile') {
|
if (deviceMode === 'mobile') {
|
||||||
editing.movedAway = true;
|
editorState().movedAway = true;
|
||||||
}
|
}
|
||||||
eSendEvent('showTooltip');
|
eSendEvent('showTooltip');
|
||||||
toolbarRef.current?.scrollTo({
|
toolbarRef.current?.scrollTo({
|
||||||
@@ -83,7 +84,7 @@ const EditorHeader = ({ editor }) => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
useEditorStore.getState().setCurrentlyEditingNote(null);
|
useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||||
}, 1);
|
}, 1);
|
||||||
editing.currentlyEditing = false;
|
editorState().currentlyEditing = false;
|
||||||
keyboardListener.current?.remove();
|
keyboardListener.current?.remove();
|
||||||
editor?.reset();
|
editor?.reset();
|
||||||
}
|
}
|
||||||
@@ -122,9 +123,9 @@ const EditorHeader = ({ editor }) => {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (editing.isFocused) {
|
if (editorState().isFocused) {
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
}
|
}
|
||||||
eSendEvent(eOpenPublishNoteDialog, note);
|
eSendEvent(eOpenPublishNoteDialog, note);
|
||||||
};
|
};
|
||||||
@@ -142,9 +143,9 @@ const EditorHeader = ({ editor }) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editing.isFocused || editing.keyboardState) {
|
if (editorState().isFocused || editorState().keyboardState) {
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Properties.present(note, ['Dark Mode']);
|
Properties.present(note, ['Dark Mode']);
|
||||||
@@ -208,13 +209,13 @@ const EditorHeader = ({ editor }) => {
|
|||||||
handleBack.current = BackHandler.addEventListener('hardwareBackPress', _onHardwareBackPress);
|
handleBack.current = BackHandler.addEventListener('hardwareBackPress', _onHardwareBackPress);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (editing.currentlyEditing) {
|
if (editorState().currentlyEditing) {
|
||||||
await _onBackPress();
|
await _onBackPress();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _onHardwareBackPress = async () => {
|
const _onHardwareBackPress = async () => {
|
||||||
if (editing.currentlyEditing) {
|
if (editorState().currentlyEditing) {
|
||||||
await _onBackPress();
|
await _onBackPress();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -280,9 +281,9 @@ const EditorHeader = ({ editor }) => {
|
|||||||
}}
|
}}
|
||||||
top={50}
|
top={50}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
if (editing.isFocused) {
|
if (editorState().isFocused) {
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
}
|
}
|
||||||
umami.pageView('/pro-screen', '/editor');
|
umami.pageView('/pro-screen', '/editor');
|
||||||
eSendEvent(eOpenPremiumDialog);
|
eSendEvent(eOpenPremiumDialog);
|
||||||
@@ -343,7 +344,7 @@ const EditorHeader = ({ editor }) => {
|
|||||||
top={50}
|
top={50}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
eSendEvent(eOpenFullscreenEditor);
|
eSendEvent(eOpenFullscreenEditor);
|
||||||
editing.isFullscreen = true;
|
editorState().isFullscreen = true;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { editing } from '../../utils';
|
|||||||
import { eOnLoadNote } from '../../utils/events';
|
import { eOnLoadNote } from '../../utils/events';
|
||||||
import { SIZE } from '../../utils/size';
|
import { SIZE } from '../../utils/size';
|
||||||
import { sleep, timeConverter } from '../../utils/time';
|
import { sleep, timeConverter } from '../../utils/time';
|
||||||
|
import { editorState } from './tiptap/utils';
|
||||||
|
|
||||||
let timer = null;
|
let timer = null;
|
||||||
let timerError = null;
|
let timerError = null;
|
||||||
@@ -21,7 +22,7 @@ const EditorOverlay = () => {
|
|||||||
const opacity = useValue(1);
|
const opacity = useValue(1);
|
||||||
|
|
||||||
const load = async _loading => {
|
const load = async _loading => {
|
||||||
editing.overlay = true;
|
editorState().overlay = true;
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
clearTimeout(timerError);
|
clearTimeout(timerError);
|
||||||
clearTimeout(timerClosing);
|
clearTimeout(timerClosing);
|
||||||
@@ -42,7 +43,7 @@ const EditorOverlay = () => {
|
|||||||
clearTimeout(timerError);
|
clearTimeout(timerError);
|
||||||
clearTimeout(timerClosing);
|
clearTimeout(timerClosing);
|
||||||
setError(false);
|
setError(false);
|
||||||
editing.overlay = false;
|
editorState().overlay = false;
|
||||||
timing(opacity, {
|
timing(opacity, {
|
||||||
toValue: 0,
|
toValue: 0,
|
||||||
duration: 150,
|
duration: 150,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { useThemeStore } from '../../stores/theme';
|
|||||||
import { editorRef } from '../../utils/global-refs';
|
import { editorRef } from '../../utils/global-refs';
|
||||||
import useIsFloatingKeyboard from '../../utils/hooks/use-is-floating-keyboard';
|
import useIsFloatingKeyboard from '../../utils/hooks/use-is-floating-keyboard';
|
||||||
import EditorOverlay from './EditorOverlay';
|
import EditorOverlay from './EditorOverlay';
|
||||||
import { textInput } from './tiptap/utils';
|
import { editorController, editorState, textInput } from './tiptap/utils';
|
||||||
|
|
||||||
export const EditorWrapper = ({ width }) => {
|
export const EditorWrapper = ({ width }) => {
|
||||||
const colors = useThemeStore(state => state.colors);
|
const colors = useThemeStore(state => state.colors);
|
||||||
@@ -27,9 +27,9 @@ export const EditorWrapper = ({ width }) => {
|
|||||||
|
|
||||||
const onAppStateChanged = async state => {
|
const onAppStateChanged = async state => {
|
||||||
if (state === 'active') {
|
if (state === 'active') {
|
||||||
// if (!editing.movedAway) {
|
if (!editorState().movedAway) {
|
||||||
// await checkStatus(false);
|
editorController.current.onReady();
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Platform, View } from 'react-native';
|
import { Platform, View } from 'react-native';
|
||||||
import { IconButton } from '../../components/ui/icon-button';
|
import { IconButton } from '../../components/ui/icon-button';
|
||||||
import { useThemeStore } from '../../stores/theme';
|
|
||||||
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
|
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
|
||||||
import { editing } from '../../utils';
|
import { useThemeStore } from '../../stores/theme';
|
||||||
import { SIZE } from '../../utils/size';
|
|
||||||
import useKeyboard from '../../utils/hooks/use-keyboard';
|
import useKeyboard from '../../utils/hooks/use-keyboard';
|
||||||
|
import { SIZE } from '../../utils/size';
|
||||||
import { EditorWebView } from './Functions';
|
import { EditorWebView } from './Functions';
|
||||||
import tiny, { safeKeyboardDismiss } from './tiny/tiny';
|
import tiny, { safeKeyboardDismiss } from './tiny/tiny';
|
||||||
|
import { editorState } from './tiptap/utils';
|
||||||
|
|
||||||
const HistoryComponent = () => {
|
const HistoryComponent = () => {
|
||||||
const colors = useThemeStore(state => state.colors);
|
const colors = useThemeStore(state => state.colors);
|
||||||
@@ -16,7 +16,7 @@ const HistoryComponent = () => {
|
|||||||
redo: false
|
redo: false
|
||||||
});
|
});
|
||||||
const keyboard = useKeyboard();
|
const keyboard = useKeyboard();
|
||||||
editing.keyboardState = keyboard.keyboardShown;
|
editorState().keyboardState = keyboard.keyboardShown;
|
||||||
|
|
||||||
const onHistoryChange = data => {
|
const onHistoryChange = data => {
|
||||||
setHistoryState(data);
|
setHistoryState(data);
|
||||||
@@ -47,7 +47,7 @@ const HistoryComponent = () => {
|
|||||||
height: 35
|
height: 35
|
||||||
}}
|
}}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
editing.keyboardState = true;
|
editorState().keyboardState = true;
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import React from 'react';
|
|||||||
import { Platform, View } from 'react-native';
|
import { Platform, View } from 'react-native';
|
||||||
import WebView from 'react-native-webview';
|
import WebView from 'react-native-webview';
|
||||||
import { notesnook } from '../../../e2e/test.ids';
|
import { notesnook } from '../../../e2e/test.ids';
|
||||||
import { useEditorStore, useUserStore } from '../../stores/stores';
|
import { useUserStore } from '../../stores/stores';
|
||||||
import EditorHeader from './EditorHeader';
|
import EditorHeader from './EditorHeader';
|
||||||
import { sourceUri, _onShouldStartLoadWithRequest } from './Functions';
|
import { sourceUri, _onShouldStartLoadWithRequest } from './Functions';
|
||||||
import { useEditor } from './tiptap/use-editor';
|
import { useEditor } from './tiptap/use-editor';
|
||||||
|
import { editorController } from './tiptap/utils';
|
||||||
|
|
||||||
const source = { uri: sourceUri + 'index.html' };
|
const source = { uri: sourceUri + 'index.html' };
|
||||||
|
|
||||||
@@ -20,8 +21,8 @@ const style = {
|
|||||||
const Editor = React.memo(
|
const Editor = React.memo(
|
||||||
() => {
|
() => {
|
||||||
const premiumUser = useUserStore(state => state.premium);
|
const premiumUser = useUserStore(state => state.premium);
|
||||||
const sessionId = useEditorStore(state => state.sessionId);
|
|
||||||
const editor = useEditor();
|
const editor = useEditor();
|
||||||
|
editorController.current = editor;
|
||||||
|
|
||||||
return editor.loading ? null : (
|
return editor.loading ? null : (
|
||||||
<>
|
<>
|
||||||
@@ -43,7 +44,7 @@ const Editor = React.memo(
|
|||||||
// onError={() => {
|
// onError={() => {
|
||||||
// onResetRequested();
|
// onResetRequested();
|
||||||
// }}
|
// }}
|
||||||
injectedJavaScript={`globalThis.sessionId="${sessionId}";`}
|
injectedJavaScript={`globalThis.sessionId="${editor.sessionId}";`}
|
||||||
javaScriptEnabled={true}
|
javaScriptEnabled={true}
|
||||||
focusable={true}
|
focusable={true}
|
||||||
keyboardDisplayRequiresUserAction={false}
|
keyboardDisplayRequiresUserAction={false}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import { editing } from '../../../utils';
|
import { editing } from '../../../utils';
|
||||||
import { EditorWebView, getWebviewInit, post } from '../Functions';
|
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() {
|
export function safeKeyboardDismiss() {
|
||||||
console.log('keyboard state', editing.keyboardState);
|
console.log('keyboard state', editorState().keyboardState);
|
||||||
if (!editing.keyboardState) return;
|
if (!editorState().keyboardState) return;
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
textInput.current?.focus();
|
textInput.current?.focus();
|
||||||
textInput.current?.blur();
|
textInput.current?.blur();
|
||||||
@@ -224,10 +224,10 @@ const redo = `tinymce.activeEditor.undoManager.redo();`;
|
|||||||
const clearHistory = `tinymce.activeEditor.undoManager.clear();`;
|
const clearHistory = `tinymce.activeEditor.undoManager.clear();`;
|
||||||
|
|
||||||
const onKeyboardShow = () => {
|
const onKeyboardShow = () => {
|
||||||
if (!editing.movedAway) {
|
if (!editorState().movedAway) {
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
if (Platform.OS === 'ios') {
|
if (Platform.OS === 'ios') {
|
||||||
if (editing.focusType === 'title') return;
|
if (editorState().focusType === 'title') return;
|
||||||
call(EditorWebView, keyboardStateChanged);
|
call(EditorWebView, keyboardStateChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { eSendEvent } from '../../../../services/event-manager';
|
|||||||
import { editing } from '../../../../utils';
|
import { editing } from '../../../../utils';
|
||||||
import { sleep } from '../../../../utils/time';
|
import { sleep } from '../../../../utils/time';
|
||||||
import { EditorWebView, textInput } from '../../Functions';
|
import { EditorWebView, textInput } from '../../Functions';
|
||||||
|
import { editorState } from '../../tiptap/utils';
|
||||||
import tiny from '../tiny';
|
import tiny from '../tiny';
|
||||||
|
|
||||||
export const properties = {
|
export const properties = {
|
||||||
@@ -34,13 +35,13 @@ export async function focusEditor(format, kill = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function reFocusEditor() {
|
export async function reFocusEditor() {
|
||||||
if (editing.isFocused === true) {
|
if (editorState().isFocused === true) {
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
await sleep(300);
|
await sleep(300);
|
||||||
textInput.current?.focus();
|
textInput.current?.focus();
|
||||||
}
|
}
|
||||||
await sleep(300);
|
await sleep(300);
|
||||||
if (editing.focusType == 'editor') {
|
if (editorState().focusType == 'editor') {
|
||||||
focusEditor(null, false);
|
focusEditor(null, false);
|
||||||
} else {
|
} else {
|
||||||
Platform.OS === 'android' && EditorWebView.current?.requestFocus();
|
Platform.OS === 'android' && EditorWebView.current?.requestFocus();
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
import ToolbarItemPin from './itempin';
|
import ToolbarItemPin from './itempin';
|
||||||
import ToolbarListFormat from './listformat';
|
import ToolbarListFormat from './listformat';
|
||||||
import { Table } from './table';
|
import { Table } from './table';
|
||||||
|
import { editorState } from '../../tiptap/utils';
|
||||||
|
|
||||||
const ToolbarItem = ({
|
const ToolbarItem = ({
|
||||||
format,
|
format,
|
||||||
@@ -90,7 +91,7 @@ const ToolbarItem = ({
|
|||||||
properties.selection = data;
|
properties.selection = data;
|
||||||
let formats = Object.keys(data);
|
let formats = Object.keys(data);
|
||||||
if (!data['link'] && type === 'tooltip') {
|
if (!data['link'] && type === 'tooltip') {
|
||||||
if (editing.tooltip) {
|
if (editorState().tooltip) {
|
||||||
eSendEvent('showTooltip');
|
eSendEvent('showTooltip');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,9 +204,9 @@ const ToolbarItem = ({
|
|||||||
const onPress = async event => {
|
const onPress = async event => {
|
||||||
if (premium && !isPro) {
|
if (premium && !isPro) {
|
||||||
let user = await db.user.getUser();
|
let user = await db.user.getUser();
|
||||||
if (editing.isFocused) {
|
if (editorState().isFocused) {
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
}
|
}
|
||||||
if (user && !isPro && !user.isEmailConfirmed) {
|
if (user && !isPro && !user.isEmailConfirmed) {
|
||||||
PremiumService.showVerifyEmailDialog();
|
PremiumService.showVerifyEmailDialog();
|
||||||
@@ -223,15 +224,15 @@ const ToolbarItem = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'settings') {
|
if (type === 'settings') {
|
||||||
if (editing.isFocused) {
|
if (editorState().isFocused) {
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
}
|
}
|
||||||
eSendEvent('openEditorSettings');
|
eSendEvent('openEditorSettings');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editing.tooltip === format && !formatValue) {
|
if (editorState().tooltip === format && !formatValue) {
|
||||||
focusEditor(format);
|
focusEditor(format);
|
||||||
eSendEvent('showTooltip');
|
eSendEvent('showTooltip');
|
||||||
|
|
||||||
@@ -316,7 +317,7 @@ const ToolbarItem = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
focusEditor(format);
|
focusEditor(format);
|
||||||
editing.tooltip = null;
|
editorState().tooltip = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isdefaultColorFormat = /^(dhilitecolor|dforecolor)$/.test(format);
|
const isdefaultColorFormat = /^(dhilitecolor|dforecolor)$/.test(format);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import tiny from '../tiny';
|
|||||||
import { execCommands } from './commands';
|
import { execCommands } from './commands';
|
||||||
import { focusEditor, formatSelection, INPUT_MODE, properties } from './constants';
|
import { focusEditor, formatSelection, INPUT_MODE, properties } from './constants';
|
||||||
import LinkPreview from './linkpreview';
|
import LinkPreview from './linkpreview';
|
||||||
|
import { editorState } from '../../tiptap/utils';
|
||||||
|
|
||||||
let inputValue = null;
|
let inputValue = null;
|
||||||
|
|
||||||
@@ -30,11 +31,11 @@ const ToolbarLinkInput = ({ format, value, setVisible }) => {
|
|||||||
}
|
}
|
||||||
inputValue = value;
|
inputValue = value;
|
||||||
properties.inputMode = value ? INPUT_MODE.NO_EDIT : INPUT_MODE.EDITING;
|
properties.inputMode = value ? INPUT_MODE.NO_EDIT : INPUT_MODE.EDITING;
|
||||||
editing.tooltip = format;
|
editorState().tooltip = format;
|
||||||
properties.userBlur = false;
|
properties.userBlur = false;
|
||||||
return () => {
|
return () => {
|
||||||
properties.inputMode = null;
|
properties.inputMode = null;
|
||||||
editing.tooltip = null;
|
editorState().tooltip = null;
|
||||||
inputValue = null;
|
inputValue = null;
|
||||||
};
|
};
|
||||||
}, [format]);
|
}, [format]);
|
||||||
@@ -87,7 +88,7 @@ const ToolbarLinkInput = ({ format, value, setVisible }) => {
|
|||||||
tiny.call(EditorWebView, tiny.clearRange);
|
tiny.call(EditorWebView, tiny.clearRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
editing.tooltip = null;
|
editorState().tooltip = null;
|
||||||
|
|
||||||
if (inputValue) {
|
if (inputValue) {
|
||||||
properties.pauseSelectionChange = true;
|
properties.pauseSelectionChange = true;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { db } from '../../../../utils/database';
|
|||||||
import { eCloseProgressDialog } from '../../../../utils/events';
|
import { eCloseProgressDialog } from '../../../../utils/events';
|
||||||
import { sleep } from '../../../../utils/time';
|
import { sleep } from '../../../../utils/time';
|
||||||
import { EditorWebView, getNote } from '../../Functions';
|
import { EditorWebView, getNote } from '../../Functions';
|
||||||
|
import { editorState } from '../../tiptap/utils';
|
||||||
import tiny, { safeKeyboardDismiss } from '../tiny';
|
import tiny, { safeKeyboardDismiss } from '../tiny';
|
||||||
|
|
||||||
const FILE_SIZE_LIMIT = 500 * 1024 * 1024;
|
const FILE_SIZE_LIMIT = 500 * 1024 * 1024;
|
||||||
@@ -199,9 +200,9 @@ const gallery = async options => {
|
|||||||
const pick = async options => {
|
const pick = async options => {
|
||||||
if (!PremiumService.get()) {
|
if (!PremiumService.get()) {
|
||||||
let user = await db.user.getUser();
|
let user = await db.user.getUser();
|
||||||
if (editing.isFocused) {
|
if (editorState().isFocused) {
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
}
|
}
|
||||||
if (user && !PremiumService.get() && !user.isEmailConfirmed) {
|
if (user && !PremiumService.get() && !user.isEmailConfirmed) {
|
||||||
PremiumService.showVerifyEmailDialog();
|
PremiumService.showVerifyEmailDialog();
|
||||||
@@ -220,9 +221,9 @@ const pick = async options => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editing.isFocused) {
|
if (editorState().isFocused) {
|
||||||
safeKeyboardDismiss();
|
safeKeyboardDismiss();
|
||||||
editing.isFocused = true;
|
editorState().isFocused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
presentSheet({
|
presentSheet({
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { ScrollView, View } from 'react-native';
|
import { ScrollView, View } from 'react-native';
|
||||||
import { useThemeStore } from '../../../../stores/theme';
|
|
||||||
import { eSubscribeEvent, eUnSubscribeEvent } from '../../../../services/event-manager';
|
import { eSubscribeEvent, eUnSubscribeEvent } from '../../../../services/event-manager';
|
||||||
import { editing } from '../../../../utils';
|
import { useThemeStore } from '../../../../stores/theme';
|
||||||
import layoutmanager from '../../../../utils/layout-manager';
|
import layoutmanager from '../../../../utils/layout-manager';
|
||||||
import { normalize } from '../../../../utils/size';
|
import { normalize } from '../../../../utils/size';
|
||||||
import { EditorWebView } from '../../Functions';
|
import { EditorWebView } from '../../Functions';
|
||||||
|
import { editorState } from '../../tiptap/utils';
|
||||||
import tiny from '../tiny';
|
import tiny from '../tiny';
|
||||||
import ColorGroup from './colorgroup';
|
import ColorGroup from './colorgroup';
|
||||||
import { properties } from './constants';
|
import { properties } from './constants';
|
||||||
@@ -28,7 +28,7 @@ const Tooltip = () => {
|
|||||||
const show = async data => {
|
const show = async data => {
|
||||||
properties.userBlur = true;
|
properties.userBlur = true;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
editing.tooltip = null;
|
editorState().tooltip = null;
|
||||||
if (group) {
|
if (group) {
|
||||||
layoutmanager.withAnimation(150);
|
layoutmanager.withAnimation(150);
|
||||||
setGroup(null);
|
setGroup(null);
|
||||||
@@ -36,14 +36,14 @@ const Tooltip = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
editing.tooltip = data.title;
|
editorState().tooltip = data.title;
|
||||||
if (!data.type) {
|
if (!data.type) {
|
||||||
data.type = data.title;
|
data.type = data.title;
|
||||||
}
|
}
|
||||||
layoutmanager.withSpringAnimation(200);
|
layoutmanager.withSpringAnimation(200);
|
||||||
setGroup(data);
|
setGroup(data);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (editing.tooltip !== 'link') {
|
if (editorState().tooltip !== 'link') {
|
||||||
properties.pauseSelectionChange = false;
|
properties.pauseSelectionChange = false;
|
||||||
}
|
}
|
||||||
tiny.call(
|
tiny.call(
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { RefObject } from 'react';
|
import { createRef, MutableRefObject, RefObject } from 'react';
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import WebView from 'react-native-webview';
|
import WebView from 'react-native-webview';
|
||||||
import { sleep } from '../../../utils/time';
|
import { sleep } from '../../../utils/time';
|
||||||
import { textInput } from './utils';
|
import { textInput } from './utils';
|
||||||
|
|
||||||
function call(webview: RefObject<WebView> | null, func?: string) {
|
function call(webview: RefObject<WebView | undefined>, func?: string) {
|
||||||
if (!webview || !func) return;
|
if (!webview || !func) return;
|
||||||
webview.current?.injectJavaScript(func);
|
webview.current?.injectJavaScript(func);
|
||||||
}
|
}
|
||||||
@@ -14,8 +14,8 @@ const fn = (fn: string) => `(() => {
|
|||||||
})();`;
|
})();`;
|
||||||
|
|
||||||
class Commands {
|
class Commands {
|
||||||
ref: RefObject<WebView> | null = null;
|
ref = createRef<WebView | undefined>();
|
||||||
constructor(ref: RefObject<WebView>) {
|
constructor(ref: MutableRefObject<WebView | undefined>) {
|
||||||
this.ref = ref;
|
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}"})`));
|
call(this.ref, fn(`statusBar.current.set({date:"${date}",saved:"${saved}"})`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
apps/mobile/src/screens/editor/tiptap/types.ts
Normal file
16
apps/mobile/src/screens/editor/tiptap/types.ts
Normal 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;
|
||||||
|
};
|
||||||
@@ -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 };
|
|
||||||
};
|
|
||||||
367
apps/mobile/src/screens/editor/tiptap/useEditor.ts
Normal file
367
apps/mobile/src/screens/editor/tiptap/useEditor.ts
Normal 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
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
78
apps/mobile/src/screens/editor/tiptap/utils.ts
Normal file
78
apps/mobile/src/screens/editor/tiptap/utils.ts
Normal 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);
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -9,11 +9,12 @@ import { eSendEvent } from '../../services/event-manager';
|
|||||||
import Navigation from '../../services/navigation';
|
import Navigation from '../../services/navigation';
|
||||||
import SearchService from '../../services/search';
|
import SearchService from '../../services/search';
|
||||||
import { useNoteStore } from '../../stores/stores';
|
import { useNoteStore } from '../../stores/stores';
|
||||||
import { editing, InteractionManager } from '../../utils';
|
import { InteractionManager } from '../../utils';
|
||||||
import { db } from '../../utils/database';
|
import { db } from '../../utils/database';
|
||||||
import { eOnLoadNote } from '../../utils/events';
|
import { eOnLoadNote } from '../../utils/events';
|
||||||
import { tabBarRef } from '../../utils/global-refs';
|
import { tabBarRef } from '../../utils/global-refs';
|
||||||
import { getNote } from '../editor/Functions';
|
import { getNote } from '../editor/Functions';
|
||||||
|
import { editorState } from '../editor/tiptap/utils';
|
||||||
|
|
||||||
export const Home = ({ navigation }) => {
|
export const Home = ({ navigation }) => {
|
||||||
const notes = useNoteStore(state => state.notes);
|
const notes = useNoteStore(state => state.notes);
|
||||||
@@ -83,8 +84,8 @@ export const Home = ({ navigation }) => {
|
|||||||
if (!DDS.isTab) {
|
if (!DDS.isTab) {
|
||||||
if (getNote()) {
|
if (getNote()) {
|
||||||
eSendEvent(eOnLoadNote, { type: 'new' });
|
eSendEvent(eOnLoadNote, { type: 'new' });
|
||||||
editing.currentlyEditing = true;
|
editorState().currentlyEditing = true;
|
||||||
editing.movedAway = false;
|
editorState().movedAway = false;
|
||||||
}
|
}
|
||||||
tabBarRef.current?.goToPage(1);
|
tabBarRef.current?.goToPage(1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
import { groupArray } from 'notes-core/utils/grouping';
|
import { groupArray } from 'notes-core/utils/grouping';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { FloatingButton } from '../../components/container/floating-button';
|
|
||||||
import { ContainerHeader } from '../../components/container/containerheader';
|
import { ContainerHeader } from '../../components/container/containerheader';
|
||||||
|
import { FloatingButton } from '../../components/container/floating-button';
|
||||||
import { Header } from '../../components/header';
|
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 List from '../../components/list';
|
||||||
import { useThemeStore } from '../../stores/theme';
|
import SelectionHeader from '../../components/selection-header';
|
||||||
import { useNoteStore } from '../../stores/stores';
|
import { MoveNotes } from '../../components/sheets/move-notes/movenote';
|
||||||
import { DDS } from '../../services/device-detection';
|
import { DDS } from '../../services/device-detection';
|
||||||
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
|
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
|
||||||
import Navigation from '../../services/navigation';
|
import Navigation from '../../services/navigation';
|
||||||
import SearchService from '../../services/search';
|
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 { db } from '../../utils/database';
|
||||||
import { eOnLoadNote, eOpenAddTopicDialog, refreshNotesPage } from '../../utils/events';
|
import { eOnLoadNote, eOpenAddTopicDialog, refreshNotesPage } from '../../utils/events';
|
||||||
import { openLinkInBrowser } from '../../utils/functions';
|
import { openLinkInBrowser } from '../../utils/functions';
|
||||||
import { tabBarRef } from '../../utils/global-refs';
|
import { tabBarRef } from '../../utils/global-refs';
|
||||||
import { getNote } from '../editor/Functions';
|
import { getNote } from '../editor/Functions';
|
||||||
|
import { editorState } from '../editor/tiptap/utils';
|
||||||
|
|
||||||
const getNotes = (params, group = true) => {
|
const getNotes = (params, group = true) => {
|
||||||
if (!params) return [];
|
if (!params) return [];
|
||||||
@@ -46,6 +47,44 @@ function getAlias(params) {
|
|||||||
return alias || '';
|
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 }) => {
|
export const Notes = ({ route, navigation }) => {
|
||||||
const colors = useThemeStore(state => state.colors);
|
const colors = useThemeStore(state => state.colors);
|
||||||
const params = useRef(route?.params);
|
const params = useRef(route?.params);
|
||||||
@@ -70,19 +109,13 @@ export const Notes = ({ route, navigation }) => {
|
|||||||
eSubscribeEvent(refreshNotesPage, init);
|
eSubscribeEvent(refreshNotesPage, init);
|
||||||
return () => {
|
return () => {
|
||||||
eUnSubscribeEvent(refreshNotesPage, init);
|
eUnSubscribeEvent(refreshNotesPage, init);
|
||||||
editing.actionAfterFirstSave = {
|
editorState().onNoteCreated = null;
|
||||||
type: null
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setActionAfterFirstSave = () => {
|
const setActionAfterFirstSave = () => {
|
||||||
if (params.current?.get === 'monographs') return;
|
if (params.current?.get === 'monographs') return;
|
||||||
editing.actionAfterFirstSave = {
|
editorState().onNoteCreated = id => onNoteCreated(id, params);
|
||||||
type: params.current?.type,
|
|
||||||
id: params.current?.id,
|
|
||||||
notebook: params.current?.notebookId
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = data => {
|
const init = data => {
|
||||||
@@ -110,18 +143,14 @@ export const Notes = ({ route, navigation }) => {
|
|||||||
InteractionManager.runAfterInteractions(() => {
|
InteractionManager.runAfterInteractions(() => {
|
||||||
setNotes([]);
|
setNotes([]);
|
||||||
}, 150);
|
}, 150);
|
||||||
editing.actionAfterFirstSave = {
|
editorState().onNoteCreated = null;
|
||||||
type: null
|
|
||||||
};
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigation.addListener('focus', onFocus);
|
navigation.addListener('focus', onFocus);
|
||||||
navigation.addListener('blur', onBlur);
|
navigation.addListener('blur', onBlur);
|
||||||
return () => {
|
return () => {
|
||||||
editing.actionAfterFirstSave = {
|
editorState().onNoteCreated = null;
|
||||||
type: null
|
|
||||||
};
|
|
||||||
navigation.removeListener('focus', onFocus);
|
navigation.removeListener('focus', onFocus);
|
||||||
navigation.removeListener('blur', onBlur);
|
navigation.removeListener('blur', onBlur);
|
||||||
};
|
};
|
||||||
@@ -162,8 +191,8 @@ export const Notes = ({ route, navigation }) => {
|
|||||||
if (!DDS.isTab) {
|
if (!DDS.isTab) {
|
||||||
if (getNote()) {
|
if (getNote()) {
|
||||||
eSendEvent(eOnLoadNote, { type: 'new' });
|
eSendEvent(eOnLoadNote, { type: 'new' });
|
||||||
editing.currentlyEditing = true;
|
editorState().currentlyEditing = true;
|
||||||
editing.movedAway = false;
|
editorState().movedAway = false;
|
||||||
}
|
}
|
||||||
tabBarRef.current?.goToPage(1);
|
tabBarRef.current?.goToPage(1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { useNoteStore } from '../stores/stores';
|
|||||||
import { DDS } from './device-detection';
|
import { DDS } from './device-detection';
|
||||||
import { eSendEvent } from './event-manager';
|
import { eSendEvent } from './event-manager';
|
||||||
import SettingsService from './settings';
|
import SettingsService from './settings';
|
||||||
|
import { editorState } from '../screens/editor/tiptap/utils';
|
||||||
|
|
||||||
const NOTIFICATION_TAG = 'notesnook';
|
const NOTIFICATION_TAG = 'notesnook';
|
||||||
const CHANNEL_ID = 'com.streetwriters.notesnook';
|
const CHANNEL_ID = 'com.streetwriters.notesnook';
|
||||||
@@ -36,7 +37,7 @@ function init() {
|
|||||||
if (Platform.OS === 'ios') return;
|
if (Platform.OS === 'ios') return;
|
||||||
PushNotification.configure({
|
PushNotification.configure({
|
||||||
onNotification: async function (notification) {
|
onNotification: async function (notification) {
|
||||||
editing.movedAway = false;
|
editorState().movedAway = false;
|
||||||
MMKV.removeItem('appState');
|
MMKV.removeItem('appState');
|
||||||
if (useNoteStore?.getState()?.loading === false) {
|
if (useNoteStore?.getState()?.loading === false) {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
|
|||||||
@@ -3,16 +3,15 @@ import { groupArray } from 'notes-core/utils/grouping';
|
|||||||
import { Dimensions, Platform } from 'react-native';
|
import { Dimensions, Platform } from 'react-native';
|
||||||
import create from 'zustand';
|
import create from 'zustand';
|
||||||
import { APP_VERSION } from '../../version';
|
import { APP_VERSION } from '../../version';
|
||||||
|
import { endSearch } from '../screens/editor/tiny/toolbar/commands';
|
||||||
import { eSubscribeEvent, eUnSubscribeEvent } from '../services/event-manager';
|
import { eSubscribeEvent, eUnSubscribeEvent } from '../services/event-manager';
|
||||||
import PremiumService from '../services/premium';
|
import PremiumService from '../services/premium';
|
||||||
import { history } from '../utils';
|
import { history } from '../utils';
|
||||||
|
import { ACCENT } from '../utils/color-scheme';
|
||||||
import { SUBSCRIPTION_STATUS } from '../utils/constants';
|
import { SUBSCRIPTION_STATUS } from '../utils/constants';
|
||||||
import { db } from '../utils/database';
|
import { db } from '../utils/database';
|
||||||
import { MMKV } from '../utils/database/mmkv';
|
import { MMKV } from '../utils/database/mmkv';
|
||||||
import layoutmanager from '../utils/layout-manager';
|
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 {
|
import {
|
||||||
Announcement,
|
Announcement,
|
||||||
EditorStore,
|
EditorStore,
|
||||||
@@ -28,7 +27,6 @@ import {
|
|||||||
TrashStore,
|
TrashStore,
|
||||||
UserStore
|
UserStore
|
||||||
} from './interfaces';
|
} from './interfaces';
|
||||||
import { ACCENT } from '../utils/color-scheme';
|
|
||||||
|
|
||||||
export const useNoteStore = create<NoteStore>((set, get) => ({
|
export const useNoteStore = create<NoteStore>((set, get) => ({
|
||||||
notes: [],
|
notes: [],
|
||||||
@@ -185,18 +183,18 @@ export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
|
|||||||
let _p = get().progress;
|
let _p = get().progress;
|
||||||
if (!_p) return;
|
if (!_p) return;
|
||||||
_p[hash] = null;
|
_p[hash] = null;
|
||||||
tiny.call(
|
// tiny.call(
|
||||||
EditorWebView,
|
// EditorWebView,
|
||||||
`
|
// `
|
||||||
(function() {
|
// (function() {
|
||||||
let progress = ${JSON.stringify({
|
// let progress = ${JSON.stringify({
|
||||||
loaded: 1,
|
// loaded: 1,
|
||||||
total: 1,
|
// total: 1,
|
||||||
hash
|
// hash
|
||||||
})}
|
// })}
|
||||||
tinymce.activeEditor._updateAttachmentProgress(progress);
|
// tinymce.activeEditor._updateAttachmentProgress(progress);
|
||||||
})()`
|
// })()`
|
||||||
);
|
// );
|
||||||
set({ progress: { ..._p } });
|
set({ progress: { ..._p } });
|
||||||
},
|
},
|
||||||
setProgress: (sent, total, hash, recieved, type) => {
|
setProgress: (sent, total, hash, recieved, type) => {
|
||||||
@@ -204,14 +202,14 @@ export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
|
|||||||
if (!_p) return;
|
if (!_p) return;
|
||||||
_p[hash] = { sent, total, hash, recieved, type };
|
_p[hash] = { sent, total, hash, recieved, type };
|
||||||
let progress = { total, hash, loaded: type === 'download' ? recieved : sent };
|
let progress = { total, hash, loaded: type === 'download' ? recieved : sent };
|
||||||
tiny.call(
|
// tiny.call(
|
||||||
EditorWebView,
|
// EditorWebView,
|
||||||
`
|
// `
|
||||||
(function() {
|
// (function() {
|
||||||
let progress = ${JSON.stringify(progress)}
|
// let progress = ${JSON.stringify(progress)}
|
||||||
tinymce.activeEditor._updateAttachmentProgress(progress);
|
// tinymce.activeEditor._updateAttachmentProgress(progress);
|
||||||
})()`
|
// })()`
|
||||||
);
|
// );
|
||||||
set({ progress: { ..._p } });
|
set({ progress: { ..._p } });
|
||||||
},
|
},
|
||||||
encryptionProgress: 0,
|
encryptionProgress: 0,
|
||||||
@@ -321,14 +319,14 @@ export const useEditorStore = create<EditorStore>((set, get) => ({
|
|||||||
set({ searchSelection: value, searchReplace: true });
|
set({ searchSelection: value, searchReplace: true });
|
||||||
};
|
};
|
||||||
eSubscribeEvent('selectionvalue', func);
|
eSubscribeEvent('selectionvalue', func);
|
||||||
tiny.call(
|
// tiny.call(
|
||||||
EditorWebView,
|
// EditorWebView,
|
||||||
`(function() {
|
// `(function() {
|
||||||
if (editor) {
|
// if (editor) {
|
||||||
reactNativeEventHandler('selectionvalue',editor.selection.getContent());
|
// reactNativeEventHandler('selectionvalue',editor.selection.getContent());
|
||||||
}
|
// }
|
||||||
})();`
|
// })();`
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,7 @@ import * as RNIap from 'react-native-iap';
|
|||||||
import { enabled } from 'react-native-privacy-snapshot';
|
import { enabled } from 'react-native-privacy-snapshot';
|
||||||
import { doInBackground, editing } from '..';
|
import { doInBackground, editing } from '..';
|
||||||
import { Walkthrough } from '../../components/walkthroughs';
|
import { Walkthrough } from '../../components/walkthroughs';
|
||||||
import {
|
import { editorState } from '../../screens/editor/tiptap/utils';
|
||||||
EditorWebView,
|
|
||||||
getNote,
|
|
||||||
getWebviewInit,
|
|
||||||
updateNoteInEditor
|
|
||||||
} from '../../screens/editor/Functions';
|
|
||||||
import tiny from '../../screens/editor/tiny/tiny';
|
|
||||||
import Backup from '../../services/backup';
|
import Backup from '../../services/backup';
|
||||||
import BiometricService from '../../services/biometrics';
|
import BiometricService from '../../services/biometrics';
|
||||||
import {
|
import {
|
||||||
@@ -42,6 +36,7 @@ import {
|
|||||||
clearAllStores,
|
clearAllStores,
|
||||||
initialize,
|
initialize,
|
||||||
useAttachmentStore,
|
useAttachmentStore,
|
||||||
|
useEditorStore,
|
||||||
useMessageStore,
|
useMessageStore,
|
||||||
useNoteStore,
|
useNoteStore,
|
||||||
useSettingStore,
|
useSettingStore,
|
||||||
@@ -73,15 +68,15 @@ export const useAppEvents = () => {
|
|||||||
|
|
||||||
const onMediaDownloaded = ({ hash, groupId, src }) => {
|
const onMediaDownloaded = ({ hash, groupId, src }) => {
|
||||||
if (groupId?.startsWith('monograph')) return;
|
if (groupId?.startsWith('monograph')) return;
|
||||||
tiny.call(
|
// tiny.call(
|
||||||
EditorWebView,
|
// EditorWebView,
|
||||||
`
|
// `
|
||||||
(function(){
|
// (function(){
|
||||||
let image = ${JSON.stringify({ hash, src })};
|
// let image = ${JSON.stringify({ hash, src })};
|
||||||
tinymce.activeEditor._replaceImage(image);
|
// tinymce.activeEditor._replaceImage(image);
|
||||||
})();
|
// })();
|
||||||
`
|
// `
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLoadingAttachmentProgress = data => {
|
const onLoadingAttachmentProgress = data => {
|
||||||
@@ -170,8 +165,10 @@ export const useAppEvents = () => {
|
|||||||
initialize();
|
initialize();
|
||||||
setLastSynced(await db.lastSynced());
|
setLastSynced(await db.lastSynced());
|
||||||
setSyncing(false);
|
setSyncing(false);
|
||||||
if (getNote()) {
|
let id = useEditorStore.getState().currentEditingNote;
|
||||||
await updateNoteInEditor();
|
let note = id && db.notes.note(id).data;
|
||||||
|
if (note) {
|
||||||
|
//await updateNoteInEditor();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -407,9 +404,7 @@ export const useAppEvents = () => {
|
|||||||
await reconnectSSE();
|
await reconnectSSE();
|
||||||
|
|
||||||
await checkIntentState();
|
await checkIntentState();
|
||||||
if (getWebviewInit()) {
|
|
||||||
await MMKV.removeItem('appState');
|
await MMKV.removeItem('appState');
|
||||||
}
|
|
||||||
let user = await db.user.getUser();
|
let user = await db.user.getUser();
|
||||||
if (user && !user.isEmailConfirmed) {
|
if (user && !user.isEmailConfirmed) {
|
||||||
try {
|
try {
|
||||||
@@ -421,7 +416,9 @@ export const useAppEvents = () => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
refValues.current.prevState = 'background';
|
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);
|
eSendEvent(eClearEditor);
|
||||||
}
|
}
|
||||||
await storeAppState();
|
await storeAppState();
|
||||||
@@ -462,12 +459,14 @@ export const useAppEvents = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function storeAppState() {
|
async function storeAppState() {
|
||||||
if (editing.currentlyEditing) {
|
if (editorState().currentlyEditing) {
|
||||||
if (getNote()?.locked) return;
|
let id = useEditorStore.getState().currentEditingNote;
|
||||||
|
let note = id && db.notes.note(id).data;
|
||||||
|
if (note?.locked) return;
|
||||||
let state = JSON.stringify({
|
let state = JSON.stringify({
|
||||||
editing: editing.currentlyEditing,
|
editing: editorState().currentlyEditing,
|
||||||
note: getNote(),
|
note: note,
|
||||||
movedAway: editing.movedAway,
|
movedAway: editorState().movedAway,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
});
|
});
|
||||||
await MMKV.setItem('appState', state);
|
await MMKV.setItem('appState', state);
|
||||||
@@ -490,7 +489,9 @@ export const useAppEvents = () => {
|
|||||||
eSendEvent(refreshNotesPage);
|
eSendEvent(refreshNotesPage);
|
||||||
}
|
}
|
||||||
if (notesAddedFromIntent || shareExtensionOpened) {
|
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);
|
eSendEvent('webviewreset', true);
|
||||||
MMKV.removeItem('shareExtensionOpened');
|
MMKV.removeItem('shareExtensionOpened');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function timeSince(date: number) {
|
|||||||
return Math.floor(seconds) < 0 ? '0s ago' : Math.floor(seconds) + 's ago';
|
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;
|
if (!timestamp) return;
|
||||||
let d = new Date(timestamp), // Convert the passed timestamp to milliseconds
|
let d = new Date(timestamp), // Convert the passed timestamp to milliseconds
|
||||||
yyyy = d.getFullYear(),
|
yyyy = d.getFullYear(),
|
||||||
|
|||||||
Reference in New Issue
Block a user