mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
mobile: migrate share to ts
This commit is contained in:
@@ -16,16 +16,22 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Note, NoteContent } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, {
|
||||
RefObject,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import { Linking, Platform, TextInput, View } from "react-native";
|
||||
import { Linking, Platform, TextInput, View, ViewStyle } from "react-native";
|
||||
import { WebView } from "react-native-webview";
|
||||
import {
|
||||
ShouldStartLoadRequest,
|
||||
WebViewMessageEvent
|
||||
} from "react-native-webview/lib/WebViewTypes";
|
||||
import { eSubscribeEvent, eUnSubscribeEvent } from "../services/event-manager";
|
||||
import { eOnLoadNote } from "../utils/events";
|
||||
import { defaultBorderRadius } from "../utils/size";
|
||||
@@ -42,7 +48,11 @@ export const EDITOR_URI = __DEV__
|
||||
? EditorMobileSourceUrl
|
||||
: EditorMobileSourceUrl;
|
||||
|
||||
export async function post(ref, type, value = null) {
|
||||
export async function post(
|
||||
ref: RefObject<any>,
|
||||
type: string,
|
||||
value: any = null
|
||||
) {
|
||||
const message = {
|
||||
type,
|
||||
value
|
||||
@@ -51,17 +61,25 @@ export async function post(ref, type, value = null) {
|
||||
}
|
||||
|
||||
const useEditor = () => {
|
||||
const ref = useRef();
|
||||
const ref = useRef<WebView>(null);
|
||||
const { colors } = useThemeColors("editor");
|
||||
const currentNote = useRef();
|
||||
const currentNote = useRef<
|
||||
Note & {
|
||||
content: NoteContent<false>;
|
||||
}
|
||||
>(undefined);
|
||||
|
||||
const postMessage = useCallback(
|
||||
async (type, data) => post(ref, type, data),
|
||||
async (type: string, data: any) => post(ref, type, data),
|
||||
[]
|
||||
);
|
||||
|
||||
const loadNote = useCallback(
|
||||
(note) => {
|
||||
(
|
||||
note: Note & {
|
||||
content: NoteContent<false>;
|
||||
}
|
||||
) => {
|
||||
postMessage("html", note.content.data);
|
||||
currentNote.current = note;
|
||||
},
|
||||
@@ -104,8 +122,11 @@ const useEditor = () => {
|
||||
return { ref, onLoad, currentNote };
|
||||
};
|
||||
|
||||
const useEditorEvents = (editor, onChange) => {
|
||||
const onMessage = (event) => {
|
||||
const useEditorEvents = (
|
||||
editor: ReturnType<typeof useEditor>,
|
||||
onChange: (data: string) => void
|
||||
) => {
|
||||
const onMessage = (event: WebViewMessageEvent) => {
|
||||
const data = event.nativeEvent.data;
|
||||
const editorMessage = JSON.parse(data);
|
||||
|
||||
@@ -118,7 +139,7 @@ const useEditorEvents = (editor, onChange) => {
|
||||
return onMessage;
|
||||
};
|
||||
|
||||
const onShouldStartLoadWithRequest = (request) => {
|
||||
const onShouldStartLoadWithRequest = (request: ShouldStartLoadRequest) => {
|
||||
if (request.url.includes("https")) {
|
||||
if (Platform.OS === "ios" && !request.isTopFrame) return true;
|
||||
Linking.openURL(request.url);
|
||||
@@ -128,7 +149,7 @@ const onShouldStartLoadWithRequest = (request) => {
|
||||
}
|
||||
};
|
||||
|
||||
const style = {
|
||||
const style: ViewStyle = {
|
||||
height: "100%",
|
||||
maxHeight: "100%",
|
||||
width: "100%",
|
||||
@@ -136,32 +157,46 @@ const style = {
|
||||
backgroundColor: "transparent"
|
||||
};
|
||||
|
||||
export const Editor = ({ onChange, onLoad, editorRef }) => {
|
||||
export type EditorRef = {
|
||||
focus: () => void;
|
||||
};
|
||||
|
||||
export const Editor = ({
|
||||
onChange,
|
||||
onLoad,
|
||||
editorRef
|
||||
}: {
|
||||
onChange: (data: string) => void;
|
||||
onLoad: () => void;
|
||||
editorRef: RefObject<EditorRef | null>;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const editor = useEditor();
|
||||
const inputRef = useRef();
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
const onMessage = useEditorEvents(editor, onChange);
|
||||
const [loading, setLoading] = useState(true);
|
||||
useLayoutEffect(() => {
|
||||
onLoad?.();
|
||||
}, [onLoad]);
|
||||
|
||||
if (editorRef) {
|
||||
editorRef.current = {
|
||||
focus: () => {
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus();
|
||||
editor.ref.current?.injectJavaScript(`(() => {
|
||||
useEffect(() => {
|
||||
if (editorRef) {
|
||||
editorRef.current = {
|
||||
focus: () => {
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus();
|
||||
editor.ref.current?.injectJavaScript(`(() => {
|
||||
const editor = document.getElementById('editor');
|
||||
if (editor) {
|
||||
editor.focus();
|
||||
}
|
||||
})();`);
|
||||
editor.ref?.current?.requestFocus();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
editor.ref?.current?.requestFocus();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View
|
||||
@@ -27,18 +27,20 @@ import { Platform } from "react-native";
|
||||
import RNFetchBlob from "react-native-blob-util";
|
||||
import WebView from "react-native-webview";
|
||||
import { Config } from "./store";
|
||||
import { db } from "../common/database";
|
||||
import { SUBSCRIPTION_STATUS } from "../utils/constants";
|
||||
|
||||
export const fetchHandle = createRef();
|
||||
export const fetchHandle = createRef<{
|
||||
processUrl: (url: string) => Promise<string | null>;
|
||||
}>();
|
||||
|
||||
export const HtmlLoadingWebViewAgent = React.memo(
|
||||
() => {
|
||||
const [source, setSource] = useState(null);
|
||||
const [clipper, setClipper] = useState(null);
|
||||
const loadHandler = useRef();
|
||||
const htmlHandler = useRef();
|
||||
const webview = useRef();
|
||||
const premium = useRef(false);
|
||||
const [source, setSource] = useState<string | null>(null);
|
||||
const [clipper, setClipper] = useState<string | null>(null);
|
||||
const loadHandler = useRef<((result?: boolean | null) => void) | null>(
|
||||
null
|
||||
);
|
||||
const htmlHandler = useRef<((html: string | null) => void) | null>(null);
|
||||
const webview = useRef<any>(null);
|
||||
const corsProxy = Config.corsProxy;
|
||||
|
||||
useImperativeHandle(
|
||||
@@ -71,12 +73,6 @@ export const HtmlLoadingWebViewAgent = React.memo(
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const user = await db.user.getUser();
|
||||
const subscriptionStatus =
|
||||
user?.subscription?.type || SUBSCRIPTION_STATUS.BASIC;
|
||||
premium.current =
|
||||
user && subscriptionStatus !== SUBSCRIPTION_STATUS.BASIC;
|
||||
|
||||
const clipperPath =
|
||||
Platform.OS === "ios"
|
||||
? RNFetchBlob.fs.dirs.MainBundleDir +
|
||||
@@ -107,7 +103,7 @@ export const HtmlLoadingWebViewAgent = React.memo(
|
||||
}}
|
||||
useSharedProcessPool={false}
|
||||
pointerEvents="none"
|
||||
onMessage={(event) => {
|
||||
onMessage={(event: any) => {
|
||||
try {
|
||||
const data = JSON.parse(event.nativeEvent.data);
|
||||
if (data && data.type === "html") {
|
||||
@@ -123,7 +119,7 @@ export const HtmlLoadingWebViewAgent = React.memo(
|
||||
console.log("Error handling webview message", e);
|
||||
}
|
||||
}}
|
||||
injectedJavaScriptBeforeContentLoaded={script(clipper, premium.current)}
|
||||
injectedJavaScriptBeforeContentLoaded={script(clipper!, corsProxy)}
|
||||
onError={() => {
|
||||
console.log("Error loading page");
|
||||
loadHandler.current?.();
|
||||
@@ -137,7 +133,7 @@ export const HtmlLoadingWebViewAgent = React.memo(
|
||||
() => true
|
||||
);
|
||||
|
||||
const script = (clipper, pro) => `
|
||||
const script = (clipper: string, corsProxy?: string): string => `
|
||||
${clipper}
|
||||
|
||||
function postMessage(type, value) {
|
||||
@@ -158,10 +154,10 @@ function postMessage(type, value) {
|
||||
postMessage("error", globalThis.Clipper.clipPage);
|
||||
} else {
|
||||
globalThis.Clipper.clipPage(document,false, {
|
||||
images: ${pro},
|
||||
images: true,
|
||||
inlineImages: false,
|
||||
styles: false,
|
||||
corsProxy: undefined
|
||||
corsProxy: ${corsProxy ? `"${corsProxy}"` : `undefined`}
|
||||
}).then(result => {
|
||||
postMessage("html", result);
|
||||
}).catch(e => {
|
||||
@@ -18,19 +18,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ScopedThemeProvider } from "@notesnook/theme";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { Modal, Platform } from "react-native";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Modal, ModalProps, Platform } from "react-native";
|
||||
import ShareView from "./share";
|
||||
import "./store";
|
||||
|
||||
const Wrapper = Platform.OS === "android" ? Modal : Fragment;
|
||||
const outerProps =
|
||||
Platform.OS === "android"
|
||||
? {
|
||||
? ({
|
||||
animationType: "fade",
|
||||
transparent: true,
|
||||
visible: true
|
||||
}
|
||||
} as ModalProps)
|
||||
: {};
|
||||
|
||||
const NotesnookShare = ({ quicknote = false }) => {
|
||||
@@ -42,10 +41,12 @@ const NotesnookShare = ({ quicknote = false }) => {
|
||||
}, []);
|
||||
return (
|
||||
<ScopedThemeProvider value="base">
|
||||
{!render ? null : (
|
||||
<Wrapper {...outerProps}>
|
||||
<ShareView quicknote={quicknote} />
|
||||
</Wrapper>
|
||||
{!render ? null : Platform.OS === "android" ? (
|
||||
<Modal {...outerProps}>
|
||||
<ShareView />
|
||||
</Modal>
|
||||
) : (
|
||||
<ShareView />
|
||||
)}
|
||||
</ScopedThemeProvider>
|
||||
);
|
||||
@@ -17,7 +17,9 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import ShareExtension from "@ammarahmed/react-native-share-extension";
|
||||
import ShareExtension, {
|
||||
ShareItem
|
||||
} from "@ammarahmed/react-native-share-extension";
|
||||
import { getPreviewData } from "@flyerhq/react-native-link-preview";
|
||||
import {
|
||||
formatBytes,
|
||||
@@ -33,6 +35,7 @@ import {
|
||||
Dimensions,
|
||||
Image,
|
||||
Keyboard,
|
||||
KeyboardEvent,
|
||||
Platform,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
@@ -53,21 +56,21 @@ import Heading from "../components/ui/typography/heading";
|
||||
import Paragraph from "../components/ui/typography/paragraph";
|
||||
import { useDBItem } from "../hooks/use-db-item";
|
||||
import { eSendEvent } from "../services/event-manager";
|
||||
import { FILE_SIZE_LIMIT, IMAGE_SIZE_LIMIT } from "../utils/constants";
|
||||
import { eOnLoadNote } from "../utils/events";
|
||||
import { NoteBundle } from "../utils/note-bundle";
|
||||
import { defaultBorderRadius, AppFontSize } from "../utils/size";
|
||||
import { AddNotebooks } from "./add-notebooks";
|
||||
import { AddTags } from "./add-tags";
|
||||
import { Editor } from "./editor";
|
||||
import { Editor, EditorRef } from "./editor";
|
||||
import { HtmlLoadingWebViewAgent, fetchHandle } from "./fetch-webview";
|
||||
import { Search } from "./search";
|
||||
import { initDatabase, useShareStore } from "./store";
|
||||
import { isTablet } from "react-native-device-info";
|
||||
|
||||
const getLinkPreview = (url) => {
|
||||
const getLinkPreview = (url: string) => {
|
||||
return getPreviewData(url, 5000);
|
||||
};
|
||||
async function sanitizeHtml(site) {
|
||||
async function sanitizeHtml(site: string) {
|
||||
try {
|
||||
let html = await fetchHandle.current?.processUrl(site);
|
||||
return html;
|
||||
@@ -76,11 +79,11 @@ async function sanitizeHtml(site) {
|
||||
}
|
||||
}
|
||||
|
||||
function makeHtmlFromUrl(url) {
|
||||
function makeHtmlFromUrl(url: string) {
|
||||
return `<a href='${url}' target='_blank'>${url}</a>`;
|
||||
}
|
||||
|
||||
function makeHtmlFromPlainText(text) {
|
||||
function makeHtmlFromPlainText(text: string) {
|
||||
if (!text) return "";
|
||||
|
||||
return `<p>${text
|
||||
@@ -88,12 +91,22 @@ function makeHtmlFromPlainText(text) {
|
||||
.replace(/(?:\r\n|\r|\n)/g, "</p><p>")}</p>`;
|
||||
}
|
||||
|
||||
let defaultNote = {
|
||||
title: null,
|
||||
id: null,
|
||||
type DefaultNote = {
|
||||
title?: string;
|
||||
id?: string;
|
||||
sessionId?: number;
|
||||
content: {
|
||||
type: "tiptap";
|
||||
data?: string;
|
||||
};
|
||||
};
|
||||
|
||||
let defaultNote: DefaultNote = {
|
||||
title: "",
|
||||
id: undefined,
|
||||
content: {
|
||||
type: "tiptap",
|
||||
data: null
|
||||
data: ""
|
||||
}
|
||||
};
|
||||
|
||||
@@ -115,32 +128,39 @@ const modes = {
|
||||
}
|
||||
};
|
||||
|
||||
declare global {
|
||||
var IS_SHARE_EXTENSION: boolean;
|
||||
var IS_MAIN_APP_RUNNING: boolean;
|
||||
}
|
||||
|
||||
const ShareView = () => {
|
||||
const { colors } = useThemeColors();
|
||||
const appendNoteId = useShareStore((state) => state.appendNote);
|
||||
const [note, setNote] = useState({ ...defaultNote });
|
||||
const noteContent = useRef("");
|
||||
const noteTitle = useRef("");
|
||||
const noteContent = useRef<string>(undefined);
|
||||
const noteTitle = useRef<string>(undefined);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingExtension, setLoadingExtension] = useState(true);
|
||||
const fullQualityImages = useIsFeatureAvailable("fullQualityImages");
|
||||
const [rawData, setRawData] = useState({
|
||||
type: null,
|
||||
value: null
|
||||
});
|
||||
const inputRef = useRef(null);
|
||||
const [rawData, setRawData] = useState<{
|
||||
type?: string;
|
||||
value?: string;
|
||||
}>({});
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
const [mode, setMode] = useState(1);
|
||||
const keyboardHeight = useRef(0);
|
||||
const { width, height } = useWindowDimensions();
|
||||
const [loadingPage, setLoadingPage] = useState(false);
|
||||
const editorRef = useRef();
|
||||
const [searchMode, setSearchMode] = useState(null);
|
||||
const [rawFiles, setRawFiles] = useState([]);
|
||||
const editorRef = useRef<EditorRef>(null);
|
||||
const [searchMode, setSearchMode] = useState<
|
||||
"appendNote" | "selectTags" | "selectNotebooks" | null
|
||||
>(null);
|
||||
const [rawFiles, setRawFiles] = useState<ShareItem[]>([]);
|
||||
|
||||
const [kh, setKh] = useState(0);
|
||||
const [compress, setCompress] = useState(true);
|
||||
globalThis["IS_SHARE_EXTENSION"] = true;
|
||||
const onKeyboardDidShow = (event) => {
|
||||
const onKeyboardDidShow = (event: KeyboardEvent) => {
|
||||
let height = Dimensions.get("screen").height - event.endCoordinates.screenY;
|
||||
keyboardHeight.current = height;
|
||||
setKh(height);
|
||||
@@ -172,7 +192,7 @@ const ShareView = () => {
|
||||
}
|
||||
}, [fullQualityImages]);
|
||||
|
||||
const showLinkPreview = async (note, link) => {
|
||||
const showLinkPreview = async (note: DefaultNote, link: string) => {
|
||||
let _note = note;
|
||||
_note.content.data = makeHtmlFromUrl(link);
|
||||
try {
|
||||
@@ -184,20 +204,33 @@ const ShareView = () => {
|
||||
return note;
|
||||
};
|
||||
|
||||
const onLoad = useCallback(() => {
|
||||
console.log(noteContent.current, "current...");
|
||||
eSendEvent(eOnLoadNote + "shareEditor", {
|
||||
id: null,
|
||||
content: {
|
||||
type: "tiptap",
|
||||
data: noteContent.current
|
||||
},
|
||||
forced: true
|
||||
});
|
||||
}, []);
|
||||
|
||||
const loadData = useCallback(
|
||||
async (isEditor) => {
|
||||
async (isEditor: boolean) => {
|
||||
try {
|
||||
if (noteContent.current) {
|
||||
onLoad();
|
||||
return;
|
||||
}
|
||||
defaultNote.content.data = null;
|
||||
defaultNote.content.data = undefined;
|
||||
setNote({ ...defaultNote });
|
||||
const data = await ShareExtension.data();
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
setRawData({
|
||||
value: ""
|
||||
value: "",
|
||||
type: "text"
|
||||
});
|
||||
if (isEditor) {
|
||||
setTimeout(() => {
|
||||
@@ -257,7 +290,6 @@ const ShareView = () => {
|
||||
}
|
||||
}
|
||||
onLoad();
|
||||
|
||||
setNote({ ...note });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -266,24 +298,12 @@ const ShareView = () => {
|
||||
[onLoad]
|
||||
);
|
||||
|
||||
const onLoad = useCallback(() => {
|
||||
console.log(noteContent.current, "current...");
|
||||
eSendEvent(eOnLoadNote + "shareEditor", {
|
||||
id: null,
|
||||
content: {
|
||||
type: "tiptap",
|
||||
data: noteContent.current
|
||||
},
|
||||
forced: true
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
await initDatabase();
|
||||
setLoadingExtension(false);
|
||||
loadData();
|
||||
loadData(false);
|
||||
useShareStore.getState().restore();
|
||||
} catch (e) {
|
||||
DatabaseLogger.error(e);
|
||||
@@ -306,22 +326,23 @@ const ShareView = () => {
|
||||
|
||||
let noteData;
|
||||
if (appendNoteId) {
|
||||
if (!(await db.notes.exists(appendNoteId))) {
|
||||
const note = await db.notes.note(appendNoteId);
|
||||
if (!note) {
|
||||
useShareStore.getState().setAppendNote(null);
|
||||
Alert.alert("The note you are trying to append to has been deleted.");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const note = await db.notes.note(appendNoteId);
|
||||
let rawContent = await db.content.get(note.contentId);
|
||||
|
||||
let rawContent = note.contentId
|
||||
? await db.content.get(note.contentId)
|
||||
: null;
|
||||
noteData = {
|
||||
content: {
|
||||
data: (rawContent?.data || "") + "<br/>" + noteContent.current,
|
||||
type: "tiptap"
|
||||
},
|
||||
id: note.id,
|
||||
id: note?.id,
|
||||
sessionId: Date.now()
|
||||
};
|
||||
} else {
|
||||
@@ -354,28 +375,30 @@ const ShareView = () => {
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const changeMode = async (m) => {
|
||||
setMode(m);
|
||||
const changeMode = async (value: number) => {
|
||||
setMode(value);
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
if (m === 2) {
|
||||
if (value === 2) {
|
||||
setLoadingPage(true);
|
||||
setTimeout(async () => {
|
||||
let html = await sanitizeHtml(rawData.value);
|
||||
noteContent.current = html;
|
||||
let html = await sanitizeHtml(rawData?.value || "");
|
||||
noteContent.current = html || "";
|
||||
setLoadingPage(false);
|
||||
onLoad();
|
||||
setNote((note) => {
|
||||
note.content.data = html;
|
||||
note.content.data = html || "";
|
||||
return { ...note };
|
||||
});
|
||||
}, 300);
|
||||
} else {
|
||||
setLoadingPage(false);
|
||||
let html = isURL(rawData.value)
|
||||
? makeHtmlFromUrl(rawData.value)
|
||||
: makeHtmlFromPlainText(rawData.value);
|
||||
let html = !rawData.value
|
||||
? ""
|
||||
: isURL(rawData?.value)
|
||||
? makeHtmlFromUrl(rawData?.value)
|
||||
: makeHtmlFromPlainText(rawData?.value);
|
||||
setNote((note) => {
|
||||
note.content.data = html;
|
||||
noteContent.current = html;
|
||||
@@ -395,7 +418,7 @@ const ShareView = () => {
|
||||
loadData(true);
|
||||
}, [loadData]);
|
||||
|
||||
const onRemoveFile = (item) => {
|
||||
const onRemoveFile = (item: ShareItem) => {
|
||||
const index = rawFiles.findIndex((file) => file.name === item.name);
|
||||
if (index > -1) {
|
||||
setRawFiles((state) => {
|
||||
@@ -529,7 +552,7 @@ const ShareView = () => {
|
||||
defaultValue={noteTitle.current}
|
||||
blurOnSubmit={false}
|
||||
onSubmitEditing={() => {
|
||||
editorRef.current.focus();
|
||||
editorRef.current?.focus();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -584,9 +607,6 @@ const ShareView = () => {
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.9}
|
||||
key={item.name}
|
||||
source={{
|
||||
uri: `file://${item.value}`
|
||||
}}
|
||||
onPress={() => onRemoveFile(item)}
|
||||
style={{
|
||||
borderRadius: defaultBorderRadius,
|
||||
@@ -599,7 +619,6 @@ const ShareView = () => {
|
||||
paddingHorizontal: 8,
|
||||
marginRight: 6
|
||||
}}
|
||||
resizeMode="cover"
|
||||
>
|
||||
<Icon
|
||||
color={colors.primary.icon}
|
||||
@@ -838,7 +857,7 @@ const ShareView = () => {
|
||||
|
||||
<View
|
||||
style={{
|
||||
height: Platform.isPad ? 150 : Platform.OS === "ios" ? 110 : 0
|
||||
height: isTablet() ? 150 : Platform.OS === "ios" ? 110 : 0
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@@ -848,7 +867,13 @@ const ShareView = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const AppendNote = ({ id, onLoad }) => {
|
||||
const AppendNote = ({
|
||||
id,
|
||||
onLoad
|
||||
}: {
|
||||
id: string;
|
||||
onLoad: (title: string) => void;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [item] = useDBItem(id, "note");
|
||||
|
||||
@@ -17,11 +17,17 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ThemeDark, ThemeLight, useThemeEngineStore } from "@notesnook/theme";
|
||||
import {
|
||||
ThemeDark,
|
||||
ThemeDefinition,
|
||||
ThemeLight,
|
||||
useThemeEngineStore
|
||||
} from "@notesnook/theme";
|
||||
import { Appearance } from "react-native";
|
||||
import { create } from "zustand";
|
||||
import { db, setupDatabase } from "../common/database";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
import { SettingStore } from "../stores/use-setting-store";
|
||||
|
||||
export async function initDatabase() {
|
||||
if (!db.isInitialized) {
|
||||
@@ -37,9 +43,10 @@ const StorageKeys = {
|
||||
appSettings: "appSettings"
|
||||
};
|
||||
|
||||
let appSettings = MMKV.getString(StorageKeys.appSettings);
|
||||
if (appSettings) {
|
||||
appSettings = JSON.parse(appSettings);
|
||||
let appSettingsJson = MMKV.getString(StorageKeys.appSettings);
|
||||
let appSettings: SettingStore["settings"] | null = null;
|
||||
if (appSettingsJson) {
|
||||
appSettings = JSON.parse(appSettingsJson) as SettingStore["settings"];
|
||||
}
|
||||
|
||||
const systemColorScheme = Appearance.getColorScheme();
|
||||
@@ -50,34 +57,48 @@ const currentColorScheme = useSystemTheme ? systemColorScheme : appColorScheme;
|
||||
const theme =
|
||||
currentColorScheme === "dark"
|
||||
? appSettings?.darkTheme
|
||||
: appSettings?.lightTheme;
|
||||
: appSettings?.lighTheme;
|
||||
|
||||
const currentTheme =
|
||||
theme || (currentColorScheme === "dark" ? ThemeDark : ThemeLight);
|
||||
|
||||
useThemeEngineStore.getState().setTheme(currentTheme);
|
||||
|
||||
export const useShareStore = create((set) => ({
|
||||
export type ShareStore = {
|
||||
theme: ThemeDefinition;
|
||||
appendNote: string | null;
|
||||
selectedTags: string[];
|
||||
selectedNotebooks: string[];
|
||||
setAppendNote: (noteId: string | null) => void;
|
||||
restore: () => void;
|
||||
setSelectedNotebooks: (selectedNotebooks: string[]) => void;
|
||||
setSelectedTags: (selectedTags: string[]) => void;
|
||||
};
|
||||
export const useShareStore = create<ShareStore>((set) => ({
|
||||
theme: currentTheme,
|
||||
appendNote: null,
|
||||
setAppendNote: (noteId) => {
|
||||
MMKV.setItem(StorageKeys.appendNote, noteId);
|
||||
if (!noteId) {
|
||||
MMKV.removeItem(StorageKeys.appendNote);
|
||||
} else {
|
||||
MMKV.setItem(StorageKeys.appendNote, noteId);
|
||||
}
|
||||
set({ appendNote: noteId });
|
||||
},
|
||||
restore: () => {
|
||||
let appendNote = MMKV.getString(StorageKeys.appendNote);
|
||||
let selectedNotebooks = MMKV.getString(StorageKeys.selectedNotebooks);
|
||||
let selectedTags = MMKV.getString(StorageKeys.selectedTag);
|
||||
appendNote = JSON.parse(appendNote);
|
||||
appendNote = appendNote;
|
||||
set({
|
||||
appendNote: appendNote,
|
||||
selectedNotebooks: selectedNotebooks ? JSON.parse(selectedNotebooks) : [],
|
||||
selectedTag: selectedTags ? JSON.parse(selectedTags) : []
|
||||
selectedTags: selectedTags ? JSON.parse(selectedTags) : []
|
||||
});
|
||||
},
|
||||
selectedTags: [],
|
||||
selectedNotebooks: [],
|
||||
setSelectedNotebooks: (selectedNotebooks) => {
|
||||
setSelectedNotebooks: (selectedNotebooks: string[]) => {
|
||||
MMKV.setItem(
|
||||
StorageKeys.selectedNotebooks,
|
||||
JSON.stringify(selectedNotebooks)
|
||||
8
apps/mobile/package-lock.json
generated
8
apps/mobile/package-lock.json
generated
@@ -14,7 +14,7 @@
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.2",
|
||||
"@ammarahmed/react-native-eventsource": "1.1.0",
|
||||
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.1",
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.3",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.8",
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.11",
|
||||
@@ -518,9 +518,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ammarahmed/react-native-share-extension": {
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-share-extension/-/react-native-share-extension-2.9.1.tgz",
|
||||
"integrity": "sha512-9ke3x9orQYb/3h13Cuk21T5YVM1cyLwDLndF22o7/ugFGAVA8VozpoFjHKlr3A6gKnp4m43zEkYfegHvUBj/gQ==",
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-share-extension/-/react-native-share-extension-2.9.3.tgz",
|
||||
"integrity": "sha512-T7PgFydfcuOWjslTtM7qJMeI9vfQEiJSxavfISRdnguHlvxO1+sttAft19srpGAlw6HH3XXe6D5iioJ2xr7lkA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-native": "^0.63.1"
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.2",
|
||||
"@ammarahmed/react-native-eventsource": "1.1.0",
|
||||
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.1",
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.3",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.8",
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.11",
|
||||
@@ -85,6 +85,7 @@
|
||||
"phone": "^3.1.14",
|
||||
"qclone": "^1.2.0",
|
||||
"react": "19.1.1",
|
||||
"react-async-hook": "^4.0.0",
|
||||
"react-native": "0.82.0",
|
||||
"react-native-actions-sheet": "0.9.7",
|
||||
"react-native-actions-shortcuts": "^1.0.1",
|
||||
@@ -145,8 +146,7 @@
|
||||
"toggle-switch-react-native": "3.2.0",
|
||||
"url": "^0.11.0",
|
||||
"validator": "^13.5.2",
|
||||
"zustand": "^4.5.5",
|
||||
"react-async-hook": "^4.0.0"
|
||||
"zustand": "^4.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.27.1",
|
||||
|
||||
Reference in New Issue
Block a user