mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
move header inside webview
This commit is contained in:
@@ -43,9 +43,9 @@ const Tabs = React.memo(
|
||||
>
|
||||
<Tab.Screen name="Notes" component={Home} />
|
||||
<Tab.Screen name="Notebooks" component={Notebooks} />
|
||||
<Tab.Screen name="Favorites" component={Favorites} />
|
||||
<Tab.Screen name="Trash" component={Trash} />
|
||||
<Tab.Screen name="Tags" component={Tags} />
|
||||
<Tab.Screen options={{ lazy: true }} name="Favorites" component={Favorites} />
|
||||
<Tab.Screen options={{ lazy: true }} name="Trash" component={Trash} />
|
||||
<Tab.Screen options={{ lazy: true }} name="Tags" component={Tags} />
|
||||
<Tab.Screen name="Settings" component={Settings} />
|
||||
<Tab.Screen options={{ lazy: true }} name="TaggedNotes" component={TaggedNotes} />
|
||||
<Tab.Screen options={{ lazy: true }} name="TopicNotes" component={TopicNotes} />
|
||||
|
||||
@@ -209,7 +209,8 @@ const EditorHeader = ({ editor }) => {
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: 12,
|
||||
height: 50,
|
||||
justifyContent: 'space-between'
|
||||
justifyContent: 'space-between',
|
||||
display: 'none'
|
||||
}}
|
||||
>
|
||||
<View
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Platform, View } from 'react-native';
|
||||
import { Linking, Platform, View } from 'react-native';
|
||||
import WebView from 'react-native-webview';
|
||||
import { notesnook } from '../../../e2e/test.ids';
|
||||
import { useUserStore } from '../../stores/use-user-store';
|
||||
import EditorHeader from './header';
|
||||
import { useEditor } from './tiptap/use-editor';
|
||||
import { editorController } from './tiptap/utils';
|
||||
import { useEditorEvents } from './tiptap/use-editor-events';
|
||||
|
||||
const sourceUri = '';
|
||||
|
||||
@@ -23,13 +24,20 @@ const Editor = React.memo(
|
||||
() => {
|
||||
const premiumUser = useUserStore(state => state.premium);
|
||||
const editor = useEditor();
|
||||
const onMessage = useEditorEvents(editor);
|
||||
editorController.current = editor;
|
||||
|
||||
const onError = () => {
|
||||
console.log('onError');
|
||||
editorController.current?.setLoading(true);
|
||||
setTimeout(() => editorController.current?.setLoading(false), 10);
|
||||
};
|
||||
|
||||
const onShouldStartLoadWithRequest = request => {
|
||||
Linking.openURL(request.url);
|
||||
return false;
|
||||
};
|
||||
|
||||
return editor.loading ? null : (
|
||||
<>
|
||||
<View
|
||||
@@ -39,7 +47,6 @@ const Editor = React.memo(
|
||||
flex: 1
|
||||
}}
|
||||
>
|
||||
<EditorHeader editor={editor} />
|
||||
<WebView
|
||||
testID={notesnook.editor.id}
|
||||
ref={editor.ref}
|
||||
@@ -49,13 +56,16 @@ const Editor = React.memo(
|
||||
injectedJavaScript={`globalThis.sessionId="${editor.sessionId}";`}
|
||||
javaScriptEnabled={true}
|
||||
focusable={true}
|
||||
setSupportMultipleWindows={false}
|
||||
overScrollMode="never"
|
||||
keyboardDisplayRequiresUserAction={false}
|
||||
// onShouldStartLoadWithRequest={_onShouldStartLoadWithRequest}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
cacheMode="LOAD_DEFAULT"
|
||||
cacheEnabled={true}
|
||||
domStorageEnabled={true}
|
||||
bounces={false}
|
||||
setBuiltInZoomControls={false}
|
||||
setDisplayZoomControls={false}
|
||||
allowFileAccess={true}
|
||||
scalesPageToFit={true}
|
||||
renderLoading={() => <View />}
|
||||
@@ -66,11 +76,11 @@ const Editor = React.memo(
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
originWhitelist={['*']}
|
||||
source={{
|
||||
uri: 'http://192.168.10.8:3000'
|
||||
uri: 'http://192.168.10.3:3000'
|
||||
}}
|
||||
style={style}
|
||||
autoManageStatusBarEnabled={false}
|
||||
onMessage={editor.onMessage}
|
||||
onMessage={onMessage}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createRef, MutableRefObject, RefObject } from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
import WebView from 'react-native-webview';
|
||||
import { db } from '../../../utils/database';
|
||||
import { sleep } from '../../../utils/time';
|
||||
@@ -8,6 +9,13 @@ import { getResponse, randId, textInput } from './utils';
|
||||
|
||||
type Action = { job: string; id: string };
|
||||
|
||||
export type Settings = {
|
||||
readonly: boolean;
|
||||
fullscreen: boolean;
|
||||
deviceMode: string;
|
||||
premium: boolean;
|
||||
};
|
||||
|
||||
async function call(webview: RefObject<WebView | undefined>, action?: Action) {
|
||||
if (!webview || !action) return;
|
||||
setImmediate(() => webview.current?.injectJavaScript(action.job));
|
||||
@@ -92,6 +100,29 @@ statusBar.current.set({date:"",saved:""});
|
||||
);
|
||||
};
|
||||
|
||||
setInsets = async (insets: EdgeInsets) => {
|
||||
logger.info('setInsets', insets);
|
||||
await call(
|
||||
this.ref,
|
||||
fn(`
|
||||
if (typeof safeAreaController !== "undefined") {
|
||||
safeAreaController.update(${JSON.stringify(insets)})
|
||||
}
|
||||
`)
|
||||
);
|
||||
};
|
||||
|
||||
setSettings = async (settings: Partial<Settings>) => {
|
||||
await call(
|
||||
this.ref,
|
||||
fn(`
|
||||
if (typeof globalThis.settingsController !== "undefined") {
|
||||
globalThis.settingsController.update(${JSON.stringify(settings)})
|
||||
}
|
||||
`)
|
||||
);
|
||||
};
|
||||
|
||||
setTags = async (note: Note | null | undefined) => {
|
||||
if (!note) return;
|
||||
let tags = note.tags
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import WebView from 'react-native-webview';
|
||||
import { DDS } from '../../../services/device-detection';
|
||||
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../../services/event-manager';
|
||||
@@ -9,14 +10,11 @@ import { useTagStore } from '../../../stores/use-tag-store';
|
||||
import { useThemeStore } from '../../../stores/use-theme-store';
|
||||
import { db } from '../../../utils/database';
|
||||
import { MMKV } from '../../../utils/database/mmkv';
|
||||
import { eOnLoadNote, eOpenTagsDialog } from '../../../utils/events';
|
||||
import filesystem from '../../../utils/filesystem';
|
||||
import { eOnLoadNote } from '../../../utils/events';
|
||||
import { tabBarRef } from '../../../utils/global-refs';
|
||||
import { timeConverter } from '../../../utils/time';
|
||||
import { AttachmentType } from '../../../utils/types';
|
||||
import Commands from './commands';
|
||||
import picker from './picker';
|
||||
import { EditorState, Note, Content, AppState, SavePayload, EditorMessage } from './types';
|
||||
import { AppState, Content, EditorState, Note, SavePayload } from './types';
|
||||
import { defaultState, EditorEvents, isEditorLoaded, makeSessionId, post } from './utils';
|
||||
|
||||
export const useEditor = () => {
|
||||
@@ -31,12 +29,17 @@ export const useEditor = () => {
|
||||
const state = useRef<Partial<EditorState>>(defaultState);
|
||||
const placeholderTip = useRef(TipManager.placeholderTip());
|
||||
const tags = useTagStore(state => state.tags);
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const postMessage = useCallback(
|
||||
async (type: string, data: any) => await post(editorRef, type, data),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
commands.setInsets(insets);
|
||||
}, [insets]);
|
||||
|
||||
useEffect(() => {
|
||||
commands.setTags(currentNote.current);
|
||||
}, [tags]);
|
||||
@@ -235,84 +238,6 @@ export const useEditor = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onMessage = useCallback(
|
||||
event => {
|
||||
const data = event.nativeEvent.data;
|
||||
let editorMessage = JSON.parse(data) as EditorMessage;
|
||||
|
||||
logger.info('editor', editorMessage.type);
|
||||
if (editorMessage.sessionId !== sessionId && editorMessage.type !== EditorEvents.status) {
|
||||
logger.error(
|
||||
'editor',
|
||||
'invalid session',
|
||||
editorMessage.type,
|
||||
sessionId,
|
||||
editorMessage.sessionId
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
switch (editorMessage.type) {
|
||||
case EditorEvents.logger:
|
||||
logger.info('editor-webview', editorMessage.value);
|
||||
break;
|
||||
case 'editor-event:content':
|
||||
saveContent({
|
||||
type: editorMessage.type,
|
||||
content: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case 'editor-event:selection':
|
||||
break;
|
||||
case 'editor-event:title':
|
||||
saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case 'editor-event:newtag':
|
||||
if (!currentNote.current) return;
|
||||
eSendEvent(eOpenTagsDialog, currentNote.current);
|
||||
break;
|
||||
case 'editor-event:tag':
|
||||
if (editorMessage.value) {
|
||||
if (!currentNote.current) return;
|
||||
db.notes
|
||||
//@ts-ignore
|
||||
?.note(currentNote.current?.id)
|
||||
.untag(editorMessage.value)
|
||||
.then(async () => {
|
||||
useTagStore.getState().setTags();
|
||||
await commands.setTags(currentNote.current);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
'ColoredNotes',
|
||||
'Notes',
|
||||
'TaggedNotes',
|
||||
'TopicNotes',
|
||||
'Tags'
|
||||
);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'editor-event:picker':
|
||||
picker.pick();
|
||||
break;
|
||||
case 'editor-event:download-attachment':
|
||||
filesystem.downloadAttachment(editorMessage.value?.hash, true);
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
'unhandled event recieved from editor: ',
|
||||
editorMessage.type,
|
||||
editorMessage.value
|
||||
);
|
||||
break;
|
||||
}
|
||||
eSendEvent(editorMessage.type, editorMessage);
|
||||
},
|
||||
[sessionId]
|
||||
);
|
||||
|
||||
const saveContent = useCallback(
|
||||
({ title, content, type }: { title?: string; content?: string; type: string }) => {
|
||||
if (type === EditorEvents.content) {
|
||||
@@ -354,6 +279,7 @@ export const useEditor = () => {
|
||||
loadNote({ ...currentNote.current, forced: true });
|
||||
} else {
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
commands.setInsets(insets);
|
||||
restoreEditorState();
|
||||
}
|
||||
}, [state, currentNote, loadNote]);
|
||||
@@ -392,7 +318,6 @@ export const useEditor = () => {
|
||||
}
|
||||
|
||||
return {
|
||||
onMessage,
|
||||
ref: editorRef,
|
||||
onLoad,
|
||||
commands,
|
||||
@@ -403,6 +328,7 @@ export const useEditor = () => {
|
||||
sessionId,
|
||||
setSessionId,
|
||||
note: currentNote,
|
||||
onReady
|
||||
onReady,
|
||||
saveContent
|
||||
};
|
||||
};
|
||||
|
||||
310
apps/mobile/src/screens/editor/tiptap/useEditorEvents.ts
Normal file
310
apps/mobile/src/screens/editor/tiptap/useEditorEvents.ts
Normal file
@@ -0,0 +1,310 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { BackHandler, InteractionManager, NativeEventSubscription } from 'react-native';
|
||||
import { Properties } from '../../../components/properties';
|
||||
import { DDS } from '../../../services/device-detection';
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent,
|
||||
ToastEvent
|
||||
} from '../../../services/event-manager';
|
||||
import Navigation from '../../../services/navigation';
|
||||
import { useEditorStore } from '../../../stores/use-editor-store';
|
||||
import { useSettingStore } from '../../../stores/use-setting-store';
|
||||
import { useTagStore } from '../../../stores/use-tag-store';
|
||||
import { useUserStore } from '../../../stores/use-user-store';
|
||||
import umami from '../../../utils/analytics/index';
|
||||
import { db } from '../../../utils/database';
|
||||
import {
|
||||
eClearEditor,
|
||||
eCloseFullscreenEditor,
|
||||
eOnLoadNote,
|
||||
eOpenLoginDialog,
|
||||
eOpenPremiumDialog,
|
||||
eOpenPublishNoteDialog,
|
||||
eOpenTagsDialog
|
||||
} from '../../../utils/events';
|
||||
import filesystem from '../../../utils/filesystem';
|
||||
import { tabBarRef } from '../../../utils/global-refs';
|
||||
import { NoteType } from '../../../utils/types';
|
||||
import picker from './picker';
|
||||
import { EditorMessage, useEditorType } from './types';
|
||||
import { editorController, EditorEvents, editorState } from './utils';
|
||||
|
||||
export const EventTypes = {
|
||||
selection: 'editor-event:selection',
|
||||
content: 'editor-event:content',
|
||||
title: 'editor-event:title',
|
||||
scroll: 'editor-event:scroll',
|
||||
history: 'editor-event:history',
|
||||
newtag: 'editor-event:newtag',
|
||||
tag: 'editor-event:tag',
|
||||
filepicker: 'editor-event:picker',
|
||||
download: 'editor-event:download-attachment',
|
||||
logger: 'native:logger',
|
||||
back: 'editor-event:back',
|
||||
pro: 'editor-event:pro',
|
||||
monograph: 'editor-event:monograph',
|
||||
properties: 'editor-event:properties'
|
||||
};
|
||||
|
||||
const publishNote = async () => {
|
||||
const user = useUserStore.getState().user;
|
||||
if (!user) {
|
||||
ToastEvent.show({
|
||||
heading: 'Login required',
|
||||
message: 'Login to publish',
|
||||
context: 'global',
|
||||
func: () => {
|
||||
eSendEvent(eOpenLoginDialog);
|
||||
},
|
||||
actionText: 'Login'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.isEmailConfirmed) {
|
||||
ToastEvent.show({
|
||||
heading: 'Email not verified',
|
||||
message: 'Please verify your email first.',
|
||||
context: 'global'
|
||||
});
|
||||
return;
|
||||
}
|
||||
const currentNote = editorController.current?.note?.current;
|
||||
if (currentNote?.id) {
|
||||
let note = db.notes?.note(currentNote.id)?.data as NoteType;
|
||||
if (note?.locked) {
|
||||
ToastEvent.show({
|
||||
heading: 'Locked notes cannot be published',
|
||||
type: 'error',
|
||||
context: 'global'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (editorState().isFocused) {
|
||||
editorState().isFocused = true;
|
||||
}
|
||||
eSendEvent(eOpenPublishNoteDialog, note);
|
||||
}
|
||||
};
|
||||
|
||||
const showActionsheet = async () => {
|
||||
const currentNote = editorController.current?.note?.current;
|
||||
if (currentNote?.id) {
|
||||
let note = db.notes?.note(currentNote.id)?.data as NoteType;
|
||||
if (!note) {
|
||||
ToastEvent.show({
|
||||
heading: 'Start writing to create a new note',
|
||||
type: 'success',
|
||||
context: 'global'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (editorState().isFocused || editorState().isFocused) {
|
||||
editorState().isFocused = true;
|
||||
}
|
||||
|
||||
Properties.present(note, ['Dark Mode']);
|
||||
}
|
||||
};
|
||||
|
||||
export const useEditorEvents = (editor: useEditorType) => {
|
||||
const deviceMode = useSettingStore(state => state.deviceMode);
|
||||
const fullscreen = useSettingStore(state => state.fullscreen);
|
||||
const handleBack = useRef<NativeEventSubscription>();
|
||||
const currentEditingNote = useEditorStore(state => state.currentEditingNote);
|
||||
const readonly = useEditorStore(state => state.readonly);
|
||||
const isPremium = useUserStore(state => state.premium);
|
||||
if (!editor) return null;
|
||||
|
||||
useEffect(() => {
|
||||
editor.commands.setSettings({
|
||||
deviceMode: deviceMode || 'mobile',
|
||||
fullscreen: fullscreen,
|
||||
premium: isPremium,
|
||||
readonly: readonly
|
||||
});
|
||||
}, [currentEditingNote, fullscreen, isPremium, readonly]);
|
||||
|
||||
const onBackPress = useCallback(async () => {
|
||||
setTimeout(async () => {
|
||||
if (deviceMode !== 'mobile' && fullscreen) {
|
||||
if (fullscreen) {
|
||||
eSendEvent(eCloseFullscreenEditor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (deviceMode === 'mobile') {
|
||||
editorState().movedAway = true;
|
||||
tabBarRef.current?.goToPage(0);
|
||||
}
|
||||
eSendEvent('historyEvent', {
|
||||
undo: 0,
|
||||
redo: 0
|
||||
});
|
||||
setImmediate(() => useEditorStore.getState().setCurrentlyEditingNote(null));
|
||||
editorState().currentlyEditing = false;
|
||||
editorController.current?.reset();
|
||||
}, 1);
|
||||
}, []);
|
||||
|
||||
const onHardwareBackPress = useCallback(() => {
|
||||
if (editorState().currentlyEditing) {
|
||||
onBackPress();
|
||||
return true;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onLoadNote = useCallback(async () => {
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
if (!DDS.isTab) {
|
||||
handleBack.current = BackHandler.addEventListener('hardwareBackPress', onHardwareBackPress);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onCallClear = useCallback(async (value: string) => {
|
||||
if (value === 'removeHandler') {
|
||||
if (handleBack.current) {
|
||||
handleBack.current.remove();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value === 'addHandler') {
|
||||
if (handleBack.current) {
|
||||
handleBack.current.remove();
|
||||
}
|
||||
|
||||
handleBack.current = BackHandler.addEventListener('hardwareBackPress', onHardwareBackPress);
|
||||
return;
|
||||
}
|
||||
if (editorState().currentlyEditing) {
|
||||
await onBackPress();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (fullscreen && DDS.isTab) {
|
||||
handleBack.current = BackHandler.addEventListener('hardwareBackPress', onHardwareBackPress);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (handleBack.current) {
|
||||
handleBack.current.remove();
|
||||
}
|
||||
};
|
||||
}, [fullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOnLoadNote, onLoadNote);
|
||||
eSubscribeEvent(eClearEditor, onCallClear);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eClearEditor, onCallClear);
|
||||
eUnSubscribeEvent(eOnLoadNote, onLoadNote);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onMessage = useCallback(
|
||||
event => {
|
||||
event;
|
||||
const data = event.nativeEvent.data;
|
||||
let editorMessage = JSON.parse(data) as EditorMessage;
|
||||
|
||||
logger.info('editor', editorMessage.type);
|
||||
if (
|
||||
editorMessage.sessionId !== editor.sessionId &&
|
||||
editorMessage.type !== EditorEvents.status
|
||||
) {
|
||||
logger.error(
|
||||
'editor',
|
||||
'invalid session',
|
||||
editorMessage.type,
|
||||
editor.sessionId,
|
||||
editorMessage.sessionId
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
switch (editorMessage.type) {
|
||||
case EventTypes.logger:
|
||||
logger.info('[WEBVIEW LOG]', editorMessage.value);
|
||||
break;
|
||||
case EventTypes.content:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
content: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case EventTypes.selection:
|
||||
break;
|
||||
case EventTypes.title:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case EventTypes.newtag:
|
||||
if (!editor.note.current) return;
|
||||
eSendEvent(eOpenTagsDialog, editor.note.current);
|
||||
break;
|
||||
case EventTypes.tag:
|
||||
if (editorMessage.value) {
|
||||
if (!editor.note.current) return;
|
||||
db.notes
|
||||
//@ts-ignore
|
||||
?.note(editor.note.current?.id)
|
||||
.untag(editorMessage.value)
|
||||
.then(async () => {
|
||||
useTagStore.getState().setTags();
|
||||
await editor.commands.setTags(editor.note.current);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
'ColoredNotes',
|
||||
'Notes',
|
||||
'TaggedNotes',
|
||||
'TopicNotes',
|
||||
'Tags'
|
||||
);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case EventTypes.filepicker:
|
||||
picker.pick();
|
||||
break;
|
||||
case EventTypes.download:
|
||||
filesystem.downloadAttachment(editorMessage.value?.hash, true);
|
||||
break;
|
||||
case EventTypes.pro:
|
||||
if (editor.state.current?.isFocused) {
|
||||
editor.state.current.isFocused = true;
|
||||
}
|
||||
umami.pageView('/pro-screen', '/editor');
|
||||
eSendEvent(eOpenPremiumDialog);
|
||||
break;
|
||||
case EventTypes.monograph:
|
||||
publishNote();
|
||||
break;
|
||||
case EventTypes.properties:
|
||||
showActionsheet();
|
||||
break;
|
||||
case EventTypes.back:
|
||||
onBackPress();
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
'unhandled event recieved from editor: ',
|
||||
editorMessage.type,
|
||||
editorMessage.value
|
||||
);
|
||||
break;
|
||||
}
|
||||
eSendEvent(editorMessage.type, editorMessage);
|
||||
},
|
||||
[editor.sessionId]
|
||||
);
|
||||
|
||||
return onMessage;
|
||||
};
|
||||
@@ -58,6 +58,10 @@ export const setOnFirstSave = (
|
||||
color?: string;
|
||||
} | null
|
||||
) => {
|
||||
if (!data) {
|
||||
editorState().onNoteCreated = null;
|
||||
return;
|
||||
}
|
||||
//@ts-ignore
|
||||
editorState().onNoteCreated = onNoteCreated(id, data);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,49 @@
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FlatList, View } from 'react-native';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ActivityIndicator, FlatList, View } from 'react-native';
|
||||
import Animated, { FadeIn, FadeInDown, Layout, ZoomIn } from 'react-native-reanimated';
|
||||
import { Empty } from '../../components/list/empty';
|
||||
import useNavigationStore from '../../stores/use-navigation-store';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { tabBarRef } from '../../utils/global-refs';
|
||||
import { useNavigationFocus } from '../../utils/hooks/use-navigation-focus';
|
||||
import { SectionItem } from './section-item';
|
||||
import { RouteParams, SettingSection } from './types';
|
||||
|
||||
const useDelayLayout = (delay: number) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let timeout = setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, delay);
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return loading;
|
||||
};
|
||||
|
||||
const Loading = () => {
|
||||
const colors = useThemeStore(state => state.colors.accent);
|
||||
|
||||
return (
|
||||
<Empty
|
||||
placeholderData={{
|
||||
paragraph: 'Personalize Notesnook the way you wish to.',
|
||||
heading: 'Minimal & meaningful',
|
||||
loading: 'Personalize Notesnook the way you wish to.'
|
||||
}}
|
||||
headerProps={{
|
||||
color: 'accent'
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Group = ({ navigation, route }: NativeStackScreenProps<RouteParams, 'SettingsGroup'>) => {
|
||||
const loading = useDelayLayout(300);
|
||||
useNavigationFocus(navigation, {
|
||||
onFocus: () => {
|
||||
tabBarRef.current?.lock();
|
||||
@@ -32,14 +68,18 @@ const Group = ({ navigation, route }: NativeStackScreenProps<RouteParams, 'Setti
|
||||
<SectionItem item={item} />
|
||||
);
|
||||
|
||||
return (
|
||||
return loading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<View>
|
||||
{route.params.sections ? (
|
||||
<Animated.View entering={FadeInDown}>
|
||||
<FlatList
|
||||
data={route.params.sections}
|
||||
keyExtractor={(item, index) => item.name || index.toString()}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user