mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-17 04:07:51 +01:00
mobile: fix all eslint warnings
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
} from "../../utils/events";
|
||||
import BaseDialog from "../dialog/base-dialog";
|
||||
import { allowedOnPlatform, renderItem } from "./functions";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const AnnouncementDialog = () => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -45,20 +46,20 @@ export const AnnouncementDialog = () => {
|
||||
eUnSubscribeEvent(eOpenAnnouncementDialog, open);
|
||||
eUnSubscribeEvent(eCloseAnnouncementDialog, close);
|
||||
};
|
||||
}, [visible]);
|
||||
}, [close, visible]);
|
||||
|
||||
const open = (data) => {
|
||||
setInfo(data);
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
const close = useCallback(() => {
|
||||
if (visible) {
|
||||
remove(info.id);
|
||||
setInfo(null);
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
}, [info.id, remove, visible]);
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
|
||||
@@ -48,6 +48,7 @@ import { Notice } from "../ui/notice";
|
||||
import { PressableButton } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const Actions = ({ attachment, setAttachments, fwdRef }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -154,7 +155,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
|
||||
}
|
||||
];
|
||||
|
||||
const getNotes = () => {
|
||||
const getNotes = useCallback(() => {
|
||||
let allNotes = db.notes.all;
|
||||
let attachmentNotes = attachment.noteIds?.map((id) => {
|
||||
let index = allNotes?.findIndex((note) => id === note.id);
|
||||
@@ -169,11 +170,11 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
|
||||
}
|
||||
});
|
||||
return attachmentNotes;
|
||||
};
|
||||
}, [attachment.noteIds]);
|
||||
|
||||
useEffect(() => {
|
||||
setNotes(getNotes());
|
||||
}, [attachment]);
|
||||
}, [attachment, getNotes]);
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
|
||||
@@ -42,9 +42,9 @@ export const AttachmentItem = ({ attachment, encryption, setAttachments }) => {
|
||||
attachment,
|
||||
encryption
|
||||
);
|
||||
const encryptionProgress = encryption
|
||||
? useAttachmentStore((state) => state.encryptionProgress)
|
||||
: null;
|
||||
const encryptionProgress = useAttachmentStore(
|
||||
(state) => state.encryptionProgress
|
||||
);
|
||||
|
||||
const onPress = () => {
|
||||
Actions.present(attachment, setAttachments, attachment.metadata.hash);
|
||||
|
||||
@@ -35,6 +35,7 @@ import { PressableButton } from "../ui/pressable";
|
||||
import Seperator from "../ui/seperator";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -128,9 +129,9 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => {
|
||||
if (currentMethod.method === "sms" || currentMethod.method === "email") {
|
||||
onSendCode();
|
||||
}
|
||||
}, [currentMethod.method]);
|
||||
}, [currentMethod.method, onSendCode]);
|
||||
|
||||
const onSendCode = async () => {
|
||||
const onSendCode = useCallback(async () => {
|
||||
if (seconds || sending) return;
|
||||
// TODO
|
||||
setSending(true);
|
||||
@@ -143,7 +144,7 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => {
|
||||
setSending(false);
|
||||
ToastEvent.error(e, "Error sending 2FA Code", "local");
|
||||
}
|
||||
};
|
||||
}, [currentMethod.method, mfaInfo.token, seconds, sending, start]);
|
||||
|
||||
return (
|
||||
<View>
|
||||
|
||||
@@ -32,6 +32,7 @@ import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { getElevation, showTooltip, TOOLTIP_POSITIONS } from "../../utils";
|
||||
import { normalize, SIZE } from "../../utils/size";
|
||||
import { PressableButton } from "../ui/pressable";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const FloatingButton = ({
|
||||
title,
|
||||
@@ -58,26 +59,29 @@ export const FloatingButton = ({
|
||||
|
||||
useEffect(() => {
|
||||
animate(selectionMode ? 150 : 0);
|
||||
}, [selectionMode]);
|
||||
}, [animate, selectionMode]);
|
||||
|
||||
function animate(toValue) {
|
||||
translate.value = withTiming(toValue, {
|
||||
duration: 250,
|
||||
easing: Easing.elastic(1)
|
||||
});
|
||||
}
|
||||
const animate = useCallback(
|
||||
(toValue) => {
|
||||
translate.value = withTiming(toValue, {
|
||||
duration: 250,
|
||||
easing: Easing.elastic(1)
|
||||
});
|
||||
},
|
||||
[translate]
|
||||
);
|
||||
|
||||
const onKeyboardHide = async () => {
|
||||
const onKeyboardHide = useCallback(async () => {
|
||||
editorState().keyboardState = false;
|
||||
if (deviceMode !== "mobile") return;
|
||||
animate(0);
|
||||
};
|
||||
}, [animate, deviceMode]);
|
||||
|
||||
const onKeyboardShow = async () => {
|
||||
const onKeyboardShow = useCallback(async () => {
|
||||
editorState().keyboardState = true;
|
||||
if (deviceMode !== "mobile") return;
|
||||
animate(150);
|
||||
};
|
||||
}, [animate, deviceMode]);
|
||||
|
||||
useEffect(() => {
|
||||
let sub1 = Keyboard.addListener("keyboardDidShow", onKeyboardShow);
|
||||
@@ -86,7 +90,7 @@ export const FloatingButton = ({
|
||||
sub1?.remove();
|
||||
sub2?.remove();
|
||||
};
|
||||
}, [deviceMode]);
|
||||
}, [deviceMode, onKeyboardHide, onKeyboardShow]);
|
||||
const paddings = {
|
||||
ios: 20,
|
||||
android: 20,
|
||||
|
||||
@@ -33,6 +33,7 @@ import Seperator from "../ui/seperator";
|
||||
import BaseDialog from "./base-dialog";
|
||||
import DialogButtons from "./dialog-buttons";
|
||||
import DialogHeader from "./dialog-header";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const Dialog = ({ context = "global" }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -63,7 +64,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
eUnSubscribeEvent(eOpenSimpleDialog, show);
|
||||
eUnSubscribeEvent(eCloseSimpleDialog, hide);
|
||||
};
|
||||
}, []);
|
||||
}, [show]);
|
||||
|
||||
const onPressPositive = async () => {
|
||||
if (dialogInfo.positivePress) {
|
||||
@@ -79,12 +80,15 @@ export const Dialog = ({ context = "global" }) => {
|
||||
hide();
|
||||
};
|
||||
|
||||
const show = (data) => {
|
||||
if (!data.context) data.context = "global";
|
||||
if (data.context !== context) return;
|
||||
setDialogInfo(data);
|
||||
setVisible(true);
|
||||
};
|
||||
const show = useCallback(
|
||||
(data) => {
|
||||
if (!data.context) data.context = "global";
|
||||
if (data.context !== context) return;
|
||||
setDialogInfo(data);
|
||||
setVisible(true);
|
||||
},
|
||||
[context]
|
||||
);
|
||||
|
||||
const hide = () => {
|
||||
setInputValue(null);
|
||||
|
||||
@@ -35,6 +35,7 @@ import { SIZE } from "../../../utils/size";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
import { PressableButton } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const offsets = [];
|
||||
let timeout = null;
|
||||
@@ -66,7 +67,7 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
|
||||
eUnSubscribeEvent(eCloseJumpToDialog, close);
|
||||
eUnSubscribeEvent(eScrollEvent, onScroll);
|
||||
};
|
||||
}, []);
|
||||
}, [open]);
|
||||
|
||||
const onScroll = (data) => {
|
||||
let y = data.y;
|
||||
@@ -80,10 +81,13 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
|
||||
}, 200);
|
||||
};
|
||||
|
||||
const open = (_type) => {
|
||||
if (_type !== type) return;
|
||||
setVisible(true);
|
||||
};
|
||||
const open = useCallback(
|
||||
(_type) => {
|
||||
if (_type !== type) return;
|
||||
setVisible(true);
|
||||
},
|
||||
[type]
|
||||
);
|
||||
|
||||
const close = () => {
|
||||
setVisible(false);
|
||||
@@ -91,9 +95,9 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
|
||||
|
||||
useEffect(() => {
|
||||
loadOffsets();
|
||||
}, [notes]);
|
||||
}, [loadOffsets, notes]);
|
||||
|
||||
const loadOffsets = () => {
|
||||
const loadOffsets = useCallback(() => {
|
||||
notes
|
||||
.filter((i) => i.type === "header")
|
||||
.map((item, index) => {
|
||||
@@ -108,7 +112,7 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
|
||||
offset = offset + ind * 100 + msgOffset;
|
||||
offsets.push(offset);
|
||||
});
|
||||
};
|
||||
}, [notes]);
|
||||
|
||||
return !visible ? null : (
|
||||
<BaseDialog
|
||||
|
||||
@@ -31,6 +31,7 @@ import { eScrollEvent } from "../../utils/events";
|
||||
import { LeftMenus } from "./left-menus";
|
||||
import { RightMenus } from "./right-menus";
|
||||
import { Title } from "./title";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const _Header = () => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -41,22 +42,25 @@ const _Header = () => {
|
||||
(state) => state.currentScreen?.name
|
||||
);
|
||||
|
||||
const onScroll = (data) => {
|
||||
if (data.y > 150) {
|
||||
if (!hide) return;
|
||||
setHide(false);
|
||||
} else {
|
||||
if (hide) return;
|
||||
setHide(true);
|
||||
}
|
||||
};
|
||||
const onScroll = useCallback(
|
||||
(data) => {
|
||||
if (data.y > 150) {
|
||||
if (!hide) return;
|
||||
setHide(false);
|
||||
} else {
|
||||
if (hide) return;
|
||||
setHide(true);
|
||||
}
|
||||
},
|
||||
[hide]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eScrollEvent, onScroll);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eScrollEvent, onScroll);
|
||||
};
|
||||
}, [hide]);
|
||||
}, [hide, onScroll]);
|
||||
|
||||
return selectionMode ? null : (
|
||||
<>
|
||||
|
||||
@@ -30,6 +30,7 @@ import { eScrollEvent } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const titleState = {};
|
||||
|
||||
@@ -46,7 +47,6 @@ export const Title = () => {
|
||||
: false
|
||||
);
|
||||
const isHidden = titleState[currentScreen.id];
|
||||
console.log(currentScreen, "header");
|
||||
const notebook =
|
||||
isTopic && currentScreen.notebookId
|
||||
? db.notebooks?.notebook(currentScreen.notebookId)?.data
|
||||
@@ -54,19 +54,22 @@ export const Title = () => {
|
||||
const title = currentScreen.title;
|
||||
const isTag = currentScreen?.name === "TaggedNotes";
|
||||
|
||||
const onScroll = (data) => {
|
||||
if (currentScreen.name !== "Notebook") {
|
||||
setHide(false);
|
||||
return;
|
||||
}
|
||||
if (data.y > 150) {
|
||||
if (!hide) return;
|
||||
setHide(false);
|
||||
} else {
|
||||
if (hide) return;
|
||||
setHide(true);
|
||||
}
|
||||
};
|
||||
const onScroll = useCallback(
|
||||
(data) => {
|
||||
if (currentScreen.name !== "Notebook") {
|
||||
setHide(false);
|
||||
return;
|
||||
}
|
||||
if (data.y > 150) {
|
||||
if (!hide) return;
|
||||
setHide(false);
|
||||
} else {
|
||||
if (hide) return;
|
||||
setHide(true);
|
||||
}
|
||||
},
|
||||
[currentScreen.name, hide]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentScreen.name === "Notebook") {
|
||||
@@ -78,18 +81,18 @@ export const Title = () => {
|
||||
} else {
|
||||
setHide(titleState[currentScreen.id]);
|
||||
}
|
||||
}, [currentScreen.id]);
|
||||
}, [currentScreen.id, currentScreen.name]);
|
||||
|
||||
useEffect(() => {
|
||||
titleState[currentScreen.id] = hide;
|
||||
}, [hide]);
|
||||
}, [currentScreen.id, hide]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eScrollEvent, onScroll);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eScrollEvent, onScroll);
|
||||
};
|
||||
}, [hide]);
|
||||
}, [hide, onScroll]);
|
||||
|
||||
function navigateToNotebook() {
|
||||
if (!isTopic) return;
|
||||
|
||||
@@ -58,6 +58,7 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { Walkthrough } from "../walkthroughs";
|
||||
import { useAppState } from "../../hooks/use-app-state";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const Launcher = React.memo(
|
||||
function Launcher() {
|
||||
@@ -75,7 +76,7 @@ const Launcher = React.memo(
|
||||
(state) => state.settings.introCompleted
|
||||
);
|
||||
const dbInitCompleted = useRef(false);
|
||||
const loadNotes = async () => {
|
||||
const loadNotes = useCallback(async () => {
|
||||
if (verifyUser) {
|
||||
return;
|
||||
}
|
||||
@@ -94,9 +95,9 @@ const Launcher = React.memo(
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}, [doAppLoadActions, setLoading, verifyUser]);
|
||||
|
||||
const init = async () => {
|
||||
const init = useCallback(async () => {
|
||||
if (!dbInitCompleted.current) {
|
||||
await RNBootSplash.hide({ fade: true });
|
||||
await loadDatabase();
|
||||
@@ -121,7 +122,7 @@ const Launcher = React.memo(
|
||||
} else {
|
||||
useUserStore.getState().setUser(await db.user?.getUser());
|
||||
}
|
||||
};
|
||||
}, [loadNotes, verifyUser]);
|
||||
|
||||
// useEffect(() => {
|
||||
// hideSplashScreen();
|
||||
@@ -134,9 +135,9 @@ const Launcher = React.memo(
|
||||
return () => {
|
||||
dbInitCompleted.current = false;
|
||||
};
|
||||
}, [loading]);
|
||||
}, [doAppLoadActions, loading]);
|
||||
|
||||
const doAppLoadActions = async () => {
|
||||
const doAppLoadActions = useCallback(async () => {
|
||||
await sleep(500);
|
||||
if (SettingsService.get().sessionExpired) {
|
||||
eSendEvent("session_expired");
|
||||
@@ -170,7 +171,7 @@ const Launcher = React.memo(
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [introCompleted]);
|
||||
|
||||
const checkAppUpdateAvailable = async () => {
|
||||
if (__DEV__) return;
|
||||
@@ -237,7 +238,7 @@ const Launcher = React.memo(
|
||||
// return false;
|
||||
};
|
||||
|
||||
const onUnlockBiometrics = async () => {
|
||||
const onUnlockBiometrics = useCallback(async () => {
|
||||
if (!(await BiometricService.isBiometryAvailable())) {
|
||||
ToastEvent.show({
|
||||
heading: "Biometrics unavailable",
|
||||
@@ -254,17 +255,17 @@ const Launcher = React.memo(
|
||||
enabled(false);
|
||||
password.current = null;
|
||||
}
|
||||
};
|
||||
}, [setVerifyUser]);
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, [verifyUser]);
|
||||
}, [init, verifyUser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (verifyUser && appState === "active") {
|
||||
onUnlockBiometrics();
|
||||
}
|
||||
}, [appState]);
|
||||
}, [appState, onUnlockBiometrics, verifyUser]);
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!password.current) return;
|
||||
|
||||
@@ -36,6 +36,7 @@ import { IconButton } from "../../ui/icon-button";
|
||||
import { Button } from "../../ui/button";
|
||||
import Sort from "../../sheets/sort";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const SectionHeader = React.memo(
|
||||
function SectionHeader({ item, index, type, color, screen }) {
|
||||
@@ -63,16 +64,16 @@ export const SectionHeader = React.memo(
|
||||
? "Default"
|
||||
: groupBy.slice(0, 1).toUpperCase() + groupBy.slice(1, groupBy.length);
|
||||
|
||||
const onUpdate = () => {
|
||||
const onUpdate = useCallback(() => {
|
||||
setGroupOptions({ ...db.settings?.getGroupOptions(type) });
|
||||
};
|
||||
}, [type]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent("groupOptionsUpdate", onUpdate);
|
||||
return () => {
|
||||
eUnSubscribeEvent("groupOptionsUpdate", onUpdate);
|
||||
};
|
||||
}, []);
|
||||
}, [onUpdate]);
|
||||
|
||||
return (
|
||||
<View
|
||||
|
||||
@@ -47,7 +47,7 @@ export const ActionStrip = ({ note, setActionStrip }) => {
|
||||
useEffect(() => {
|
||||
if (note.type === "note") return;
|
||||
setIsPinnedToMenu(db.settings.isPinned(note.id));
|
||||
}, []);
|
||||
}, [note.id, note.type]);
|
||||
|
||||
const updateNotes = () => {
|
||||
Navigation.queueRoutesForUpdate(
|
||||
|
||||
@@ -50,7 +50,14 @@ export const SelectionIcon = ({ setActionStrip, item, compactMode }) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [selectedItemsList, item.id]);
|
||||
}, [
|
||||
selectedItemsList,
|
||||
item.id,
|
||||
selectionMode,
|
||||
setActionStrip,
|
||||
item.dateCreated,
|
||||
selected
|
||||
]);
|
||||
|
||||
const onPress = () => {
|
||||
setSelectedItem(item);
|
||||
|
||||
@@ -105,7 +105,7 @@ const List = ({
|
||||
screen={screen}
|
||||
/>
|
||||
),
|
||||
[]
|
||||
[headerProps.color, headerProps.heading, screen, type]
|
||||
);
|
||||
|
||||
const _onRefresh = async () => {
|
||||
|
||||
@@ -43,11 +43,10 @@ export default function NoteHistory({ note, fwdRef }) {
|
||||
setHistory([...(await db.noteHistory.get(note.id))]);
|
||||
setLoading(false);
|
||||
})();
|
||||
}, []);
|
||||
}, [note.id]);
|
||||
|
||||
async function preview(item) {
|
||||
const preview = useCallback(async (item) => {
|
||||
let content = await db.noteHistory.content(item.id);
|
||||
|
||||
presentSheet({
|
||||
component: (
|
||||
<NotePreview
|
||||
@@ -60,7 +59,7 @@ export default function NoteHistory({ note, fwdRef }) {
|
||||
),
|
||||
context: "note_history"
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getDate = (start, end) => {
|
||||
let _start = timeConverter(start);
|
||||
@@ -94,7 +93,7 @@ export default function NoteHistory({ note, fwdRef }) {
|
||||
</Paragraph>
|
||||
</PressableButton>
|
||||
),
|
||||
[]
|
||||
[colors.icon, preview]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -38,31 +38,35 @@ import { sleep } from "../../utils/time";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [msg, setMsg] = useState(null);
|
||||
const timer = useRef();
|
||||
|
||||
const open = (event) => {
|
||||
if (!event) {
|
||||
clearTimeout(timer);
|
||||
timer.current = null;
|
||||
setMsg(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.context === context && msg?.desc !== event.desc) {
|
||||
if (timer.current !== null) {
|
||||
clearTimeout(timer.current);
|
||||
const open = useCallback(
|
||||
(event) => {
|
||||
if (!event) {
|
||||
clearTimeout(timer);
|
||||
timer.current = null;
|
||||
}
|
||||
setMsg(event);
|
||||
timer.current = setTimeout(async () => {
|
||||
setMsg(null);
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.context === context && msg?.desc !== event.desc) {
|
||||
if (timer.current !== null) {
|
||||
clearTimeout(timer.current);
|
||||
timer.current = null;
|
||||
}
|
||||
setMsg(event);
|
||||
timer.current = setTimeout(async () => {
|
||||
setMsg(null);
|
||||
}, 3000);
|
||||
}
|
||||
},
|
||||
[context, msg?.desc]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eShowGetPremium, open);
|
||||
@@ -70,7 +74,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
clearTimeout(timer.current);
|
||||
eUnSubscribeEvent(eShowGetPremium, open);
|
||||
};
|
||||
}, []);
|
||||
}, [open]);
|
||||
|
||||
const onPress = async () => {
|
||||
open(null);
|
||||
|
||||
@@ -47,6 +47,7 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { Walkthrough } from "../walkthroughs";
|
||||
import { PricingItem } from "./pricing-item";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const promoCyclesMonthly = {
|
||||
1: "first month",
|
||||
@@ -77,7 +78,7 @@ export const PricingPlans = ({
|
||||
const yearlyPlan = usePricing("yearly");
|
||||
const monthlyPlan = usePricing("monthly");
|
||||
|
||||
const getSkus = async () => {
|
||||
const getSkus = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
if (promo?.promoCode) {
|
||||
@@ -88,7 +89,7 @@ export const PricingPlans = ({
|
||||
setLoading(false);
|
||||
console.log("error getting sku", e);
|
||||
}
|
||||
};
|
||||
}, [promo?.promoCode]);
|
||||
|
||||
const getPromo = async (code) => {
|
||||
try {
|
||||
@@ -129,7 +130,7 @@ export const PricingPlans = ({
|
||||
|
||||
useEffect(() => {
|
||||
getSkus();
|
||||
}, []);
|
||||
}, [getSkus]);
|
||||
|
||||
const buySubscription = async (product) => {
|
||||
if (buying) return;
|
||||
|
||||
@@ -16,24 +16,23 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { BackHandler, Platform, View } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { db } from "../../common/database";
|
||||
import { eSendEvent, ToastEvent } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { db } from "../../common/database";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { eOpenMoveNoteDialog } from "../../utils/events";
|
||||
import { deleteItems } from "../../utils/functions";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import layoutmanager from "../../utils/layout-manager";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
|
||||
export const SelectionHeader = React.memo(() => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -131,11 +130,10 @@ export const SelectionHeader = React.memo(() => {
|
||||
});
|
||||
};
|
||||
|
||||
const onBackPress = () => {
|
||||
layoutmanager.withSpringAnimation(500);
|
||||
const onBackPress = useCallback(() => {
|
||||
clearSelection();
|
||||
return true;
|
||||
};
|
||||
}, [clearSelection]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectionMode) {
|
||||
@@ -143,7 +141,7 @@ export const SelectionHeader = React.memo(() => {
|
||||
} else {
|
||||
BackHandler.removeEventListener("hardwareBackPress", onBackPress);
|
||||
}
|
||||
}, [selectionMode]);
|
||||
}, [onBackPress, selectionMode]);
|
||||
|
||||
return !selectionMode ? null : (
|
||||
<View
|
||||
|
||||
@@ -32,6 +32,7 @@ import { Button } from "../ui/button";
|
||||
import SheetWrapper from "../ui/sheet";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
const SheetProvider = ({ context = "global" }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [visible, setVisible] = useState(false);
|
||||
@@ -48,26 +49,29 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
eUnSubscribeEvent(eOpenProgressDialog, open);
|
||||
eUnSubscribeEvent(eCloseProgressDialog, close);
|
||||
};
|
||||
}, [visible]);
|
||||
}, [close, open, visible]);
|
||||
|
||||
const open = async (data) => {
|
||||
if (!data.context) data.context = "global";
|
||||
if (data.context !== context) return;
|
||||
if (visible || dialogData) {
|
||||
setDialogData(null);
|
||||
setVisible(false);
|
||||
await sleep(500);
|
||||
}
|
||||
setDialogData(data);
|
||||
setVisible(true);
|
||||
if (data.editor) {
|
||||
editor.current.refocus = false;
|
||||
if (editorState().keyboardState) {
|
||||
// tiny.call(EditorWebView, tiny.cacheRange + tiny.blur);
|
||||
editor.current.refocus = true;
|
||||
const open = useCallback(
|
||||
async (data) => {
|
||||
if (!data.context) data.context = "global";
|
||||
if (data.context !== context) return;
|
||||
if (visible || dialogData) {
|
||||
setDialogData(null);
|
||||
setVisible(false);
|
||||
await sleep(500);
|
||||
}
|
||||
}
|
||||
};
|
||||
setDialogData(data);
|
||||
setVisible(true);
|
||||
if (data.editor) {
|
||||
editor.current.refocus = false;
|
||||
if (editorState().keyboardState) {
|
||||
// tiny.call(EditorWebView, tiny.cacheRange + tiny.blur);
|
||||
editor.current.refocus = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
[context, dialogData, visible]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
@@ -85,11 +89,14 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
})();
|
||||
}, [visible, dialogData]);
|
||||
|
||||
const close = (ctx) => {
|
||||
if (!ctx) ctx = "global";
|
||||
if (ctx !== context) return;
|
||||
actionSheetRef.current?.setModalVisible(false);
|
||||
};
|
||||
const close = useCallback(
|
||||
(ctx) => {
|
||||
if (!ctx) ctx = "global";
|
||||
if (ctx !== context) return;
|
||||
actionSheetRef.current?.setModalVisible(false);
|
||||
},
|
||||
[context]
|
||||
);
|
||||
|
||||
return !visible || !dialogData ? null : (
|
||||
<SheetWrapper
|
||||
|
||||
@@ -45,6 +45,7 @@ import { PressableButton } from "../../ui/pressable";
|
||||
import SheetWrapper from "../../ui/sheet";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
let newNotebookTitle = null;
|
||||
const notebookInput = createRef();
|
||||
const actionSheetRef = createRef();
|
||||
@@ -178,9 +179,9 @@ const MoveNoteComponent = ({ note }) => {
|
||||
|
||||
useEffect(() => {
|
||||
updateNoteExists();
|
||||
}, []);
|
||||
}, [updateNoteExists]);
|
||||
|
||||
const updateNoteExists = () => {
|
||||
const updateNoteExists = useCallback(() => {
|
||||
if (!note?.id && selectedItemsList?.length === 0) return;
|
||||
|
||||
let notes =
|
||||
@@ -208,7 +209,7 @@ const MoveNoteComponent = ({ note }) => {
|
||||
}
|
||||
console.log("ids: ", ids);
|
||||
setNoteExists(ids);
|
||||
};
|
||||
}, [note?.id, selectedItemsList]);
|
||||
|
||||
const openAddTopicDialog = (item) => {
|
||||
presentDialog({
|
||||
|
||||
@@ -36,6 +36,7 @@ import { PressableButton } from "../../ui/pressable";
|
||||
import SheetWrapper from "../../ui/sheet";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
const ManageTagsSheet = () => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [visible, setVisible] = useState(false);
|
||||
@@ -53,16 +54,16 @@ const ManageTagsSheet = () => {
|
||||
eUnSubscribeEvent(eOpenTagsDialog, open);
|
||||
eUnSubscribeEvent(eCloseTagsDialog, close);
|
||||
};
|
||||
}, []);
|
||||
}, [open]);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
console.log("sorting tags");
|
||||
sortTags();
|
||||
}
|
||||
}, [allTags, note, query, visible]);
|
||||
}, [allTags, note, query, sortTags, visible]);
|
||||
|
||||
const sortTags = () => {
|
||||
const sortTags = useCallback(() => {
|
||||
let _tags = [...allTags];
|
||||
_tags = _tags.filter((t) => t.type === "tag");
|
||||
_tags = _tags.sort((a, b) => a.title.localeCompare(b.title));
|
||||
@@ -85,14 +86,17 @@ const ManageTagsSheet = () => {
|
||||
noteTags = noteTags.sort((a, b) => a.title.localeCompare(b.title));
|
||||
let combinedTags = [...noteTags, ..._tags];
|
||||
setTags(combinedTags);
|
||||
};
|
||||
}, [allTags, note, query]);
|
||||
|
||||
const open = (item) => {
|
||||
setNote(item);
|
||||
useTagStore.getState().setTags();
|
||||
sortTags();
|
||||
setVisible(true);
|
||||
};
|
||||
const open = useCallback(
|
||||
(item) => {
|
||||
setNote(item);
|
||||
useTagStore.getState().setTags();
|
||||
sortTags();
|
||||
setVisible(true);
|
||||
},
|
||||
[sortTags]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { createRef, useEffect, useState } from "react";
|
||||
import React, { createRef, useCallback, useEffect, useState } from "react";
|
||||
import { ActivityIndicator, Platform, View } from "react-native";
|
||||
import DocumentPicker from "react-native-document-picker";
|
||||
import { FlatList } from "react-native-gesture-handler";
|
||||
@@ -54,7 +54,7 @@ const RestoreDataSheet = () => {
|
||||
eUnSubscribeEvent(eOpenRestoreDialog, open);
|
||||
eUnSubscribeEvent(eCloseRestoreDialog, close);
|
||||
};
|
||||
}, []);
|
||||
}, [close]);
|
||||
|
||||
const open = async () => {
|
||||
setVisible(true);
|
||||
@@ -62,7 +62,7 @@ const RestoreDataSheet = () => {
|
||||
actionSheetRef.current?.setModalVisible(true);
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
const close = useCallback(() => {
|
||||
if (restoring) {
|
||||
showIsWorking();
|
||||
return;
|
||||
@@ -71,7 +71,7 @@ const RestoreDataSheet = () => {
|
||||
setTimeout(() => {
|
||||
setVisible(false);
|
||||
}, 300);
|
||||
};
|
||||
}, [restoring]);
|
||||
|
||||
const showIsWorking = () => {
|
||||
ToastEvent.show({
|
||||
|
||||
@@ -76,7 +76,7 @@ export const Update = ({ version: appVersion, fwdRef }) => {
|
||||
}
|
||||
})();
|
||||
}
|
||||
}, []);
|
||||
}, [version]);
|
||||
|
||||
return (
|
||||
<View
|
||||
|
||||
@@ -31,6 +31,7 @@ import { PressableButton } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { ColoredNotes } from "../../screens/notes/colored";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const ColorSection = React.memo(
|
||||
function ColorSection() {
|
||||
@@ -42,7 +43,7 @@ export const ColorSection = React.memo(
|
||||
if (!loading) {
|
||||
setColorNotes();
|
||||
}
|
||||
}, [loading]);
|
||||
}, [loading, setColorNotes]);
|
||||
|
||||
return colorNotes.map((item, index) => {
|
||||
let alias = db.colors.alias(item.id);
|
||||
@@ -61,25 +62,28 @@ const ColorItem = React.memo(
|
||||
const [headerTextState, setHeaderTextState] = useState(null);
|
||||
alias = db.colors.alias(item.id) || "";
|
||||
|
||||
const onHeaderStateChange = (state) => {
|
||||
setTimeout(() => {
|
||||
let id = state.currentScreen?.id;
|
||||
if (id === item.id) {
|
||||
setHeaderTextState({ id: state.currentScreen.id });
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState(null);
|
||||
const onHeaderStateChange = useCallback(
|
||||
(state) => {
|
||||
setTimeout(() => {
|
||||
let id = state.currentScreen?.id;
|
||||
if (id === item.id) {
|
||||
setHeaderTextState({ id: state.currentScreen.id });
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
}, 300);
|
||||
},
|
||||
[headerTextState, item.id]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let unsub = useNavigationStore.subscribe(onHeaderStateChange);
|
||||
return () => {
|
||||
unsub();
|
||||
};
|
||||
}, [headerTextState]);
|
||||
}, [headerTextState, onHeaderStateChange]);
|
||||
|
||||
const onPress = (item) => {
|
||||
ColoredNotes.navigate(item, false);
|
||||
|
||||
@@ -96,7 +96,7 @@ export const SideMenu = React.memo(
|
||||
<TagsSection />
|
||||
</>
|
||||
),
|
||||
[]
|
||||
[noTextMode]
|
||||
);
|
||||
|
||||
return !loading && introCompleted ? (
|
||||
|
||||
@@ -28,6 +28,7 @@ import { Button } from "../ui/button";
|
||||
import { PressableButton } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const MenuItem = React.memo(
|
||||
function MenuItem({ item, index, testID, rightBtn }) {
|
||||
@@ -51,25 +52,28 @@ export const MenuItem = React.memo(
|
||||
}
|
||||
};
|
||||
|
||||
const onHeaderStateChange = (state) => {
|
||||
setTimeout(() => {
|
||||
let id = state.currentScreen?.id;
|
||||
if (id === screenId) {
|
||||
setHeaderTextState({ id: state.currentScreen.id });
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState(null);
|
||||
const onHeaderStateChange = useCallback(
|
||||
(state) => {
|
||||
setTimeout(() => {
|
||||
let id = state.currentScreen?.id;
|
||||
if (id === screenId) {
|
||||
setHeaderTextState({ id: state.currentScreen.id });
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
}, 300);
|
||||
},
|
||||
[headerTextState, screenId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let unsub = useNavigationStore.subscribe(onHeaderStateChange);
|
||||
return () => {
|
||||
unsub();
|
||||
};
|
||||
}, [headerTextState]);
|
||||
}, [headerTextState, onHeaderStateChange]);
|
||||
|
||||
return (
|
||||
<PressableButton
|
||||
|
||||
@@ -37,6 +37,7 @@ import Seperator from "../ui/seperator";
|
||||
import SheetWrapper from "../ui/sheet";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const TagsSection = React.memo(
|
||||
function TagsSection() {
|
||||
@@ -48,7 +49,7 @@ export const TagsSection = React.memo(
|
||||
if (!loading) {
|
||||
setMenuPins();
|
||||
}
|
||||
}, [loading]);
|
||||
}, [loading, setMenuPins]);
|
||||
|
||||
const onPress = (item) => {
|
||||
if (item.type === "notebook") {
|
||||
@@ -109,27 +110,30 @@ export const PinItem = React.memo(
|
||||
const color = headerTextState?.id === item.id ? colors.accent : colors.pri;
|
||||
const fwdRef = useRef();
|
||||
|
||||
const onHeaderStateChange = (state) => {
|
||||
setTimeout(() => {
|
||||
let id = state.currentScreen?.id;
|
||||
if (id === item.id) {
|
||||
setHeaderTextState({
|
||||
id: state.currentScreen.id
|
||||
});
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState(null);
|
||||
const onHeaderStateChange = useCallback(
|
||||
(state) => {
|
||||
setTimeout(() => {
|
||||
let id = state.currentScreen?.id;
|
||||
if (id === item.id) {
|
||||
setHeaderTextState({
|
||||
id: state.currentScreen.id
|
||||
});
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
}, 300);
|
||||
},
|
||||
[headerTextState, item.id]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let unsub = useNavigationStore.subscribe(onHeaderStateChange);
|
||||
return () => {
|
||||
unsub();
|
||||
};
|
||||
}, [headerTextState]);
|
||||
}, [headerTextState, onHeaderStateChange]);
|
||||
|
||||
const icons = {
|
||||
topic: "bookmark",
|
||||
|
||||
@@ -126,7 +126,16 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
return () => {
|
||||
sub && sub.remove();
|
||||
};
|
||||
}, [introCompleted, deviceMode, widths]);
|
||||
}, [
|
||||
introCompleted,
|
||||
deviceMode,
|
||||
widths,
|
||||
fullscreen,
|
||||
translateX,
|
||||
isDrawerOpen,
|
||||
homePosition,
|
||||
onDrawerStateChange
|
||||
]);
|
||||
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
@@ -193,7 +202,16 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
setScrollEnabled: () => true,
|
||||
node: node
|
||||
}),
|
||||
[deviceMode, homePosition, editorPosition]
|
||||
[
|
||||
currentTab,
|
||||
deviceMode,
|
||||
translateX,
|
||||
onDrawerStateChange,
|
||||
homePosition,
|
||||
editorPosition,
|
||||
forcedLock,
|
||||
isDrawerOpen
|
||||
]
|
||||
);
|
||||
|
||||
useAnimatedReaction(
|
||||
|
||||
@@ -34,6 +34,7 @@ import { SIZE } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
let toastMessages = [];
|
||||
export const Toast = ({ context = "global" }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -43,42 +44,46 @@ export const Toast = ({ context = "global" }) => {
|
||||
const hideTimeout = useRef();
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const showToastFunc = async (data) => {
|
||||
console.log("toast show", data.message, toastMessages.length);
|
||||
if (!data) return;
|
||||
if (data.context !== context) return;
|
||||
if (toastMessages.findIndex((m) => m.message === data.message) >= 0) {
|
||||
console.log("returning from here");
|
||||
return;
|
||||
}
|
||||
toastMessages.push(data);
|
||||
if (toastMessages?.length > 1) return;
|
||||
setData(data);
|
||||
const showToastFunc = useCallback(
|
||||
async (data) => {
|
||||
if (!data) return;
|
||||
if (data.context !== context) return;
|
||||
if (toastMessages.findIndex((m) => m.message === data.message) >= 0) {
|
||||
return;
|
||||
}
|
||||
toastMessages.push(data);
|
||||
if (toastMessages?.length > 1) return;
|
||||
setData(data);
|
||||
|
||||
setVisible(true);
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToastFunc();
|
||||
}, data.duration);
|
||||
};
|
||||
setVisible(true);
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToastFunc();
|
||||
}, data.duration);
|
||||
},
|
||||
[context, hideToastFunc]
|
||||
);
|
||||
|
||||
const showNext = (data) => {
|
||||
if (!data) {
|
||||
hideToastFunc();
|
||||
return;
|
||||
}
|
||||
setData(data);
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToastFunc();
|
||||
}, data?.duration);
|
||||
};
|
||||
const showNext = useCallback(
|
||||
(data) => {
|
||||
if (!data) {
|
||||
hideToastFunc();
|
||||
return;
|
||||
}
|
||||
setData(data);
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToastFunc();
|
||||
}, data?.duration);
|
||||
},
|
||||
[hideToastFunc]
|
||||
);
|
||||
|
||||
const hideToastFunc = () => {
|
||||
const hideToastFunc = useCallback(() => {
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
@@ -100,7 +105,7 @@ export const Toast = ({ context = "global" }) => {
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
}, [showNext]);
|
||||
|
||||
const _onKeyboardShow = () => {
|
||||
setKeyboard(true);
|
||||
@@ -127,7 +132,7 @@ export const Toast = ({ context = "global" }) => {
|
||||
eUnSubscribeEvent(eShowToast, showToastFunc);
|
||||
eUnSubscribeEvent(eHideToast, hideToastFunc);
|
||||
};
|
||||
}, [keyboard]);
|
||||
}, [hideToastFunc, keyboard, showToastFunc]);
|
||||
|
||||
return (
|
||||
visible && (
|
||||
|
||||
@@ -105,7 +105,7 @@ export const PressableButton = ({
|
||||
},
|
||||
customStyle
|
||||
],
|
||||
[customStyle, noborder, type, colors]
|
||||
[alpha, selectedColor, opacity, primaryColor, noborder, customStyle]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -65,7 +65,7 @@ const SheetWrapper = ({
|
||||
borderBottomRightRadius: 0,
|
||||
borderBottomLeftRadius: 0
|
||||
};
|
||||
}, [colors.bg, gestureEnabled]);
|
||||
}, [colors.bg, largeTablet, smallTablet, width]);
|
||||
|
||||
const _onOpen = () => {
|
||||
onOpen && onOpen();
|
||||
|
||||
@@ -49,7 +49,7 @@ export const BouncingView = ({
|
||||
duration: duration,
|
||||
easing: Easing.elastic(1)
|
||||
});
|
||||
}, []);
|
||||
}, [animated, duration, initialScale, scale]);
|
||||
|
||||
return (
|
||||
<Animated.View style={[style, animatedStyle]}>{children}</Animated.View>
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
} from "../utils/events";
|
||||
import { deleteItems } from "../utils/functions";
|
||||
import { sleep } from "../utils/time";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const useActions = ({ close = () => null, item }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -78,9 +79,9 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
if (item.type !== "note") {
|
||||
setIsPinnedToMenu(db.settings.isPinned(item.id));
|
||||
}
|
||||
}, [item]);
|
||||
}, [checkNotifPinned, item]);
|
||||
|
||||
function checkNotifPinned() {
|
||||
const checkNotifPinned = useCallback(() => {
|
||||
let pinned = Notifications.getPinnedNotes();
|
||||
if (!pinned) {
|
||||
setNotifPinned(null);
|
||||
@@ -93,7 +94,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
} else {
|
||||
setNotifPinned(null);
|
||||
}
|
||||
}
|
||||
}, [item.id]);
|
||||
|
||||
const isNoteInTopic = () => {
|
||||
const currentScreen = useNavigationStore.getState().currentScreen;
|
||||
@@ -104,13 +105,16 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
.has(item.id);
|
||||
};
|
||||
|
||||
const onUpdate = async (type) => {
|
||||
if (type === "unpin") {
|
||||
await sleep(1000);
|
||||
await Notifications.get();
|
||||
checkNotifPinned();
|
||||
}
|
||||
};
|
||||
const onUpdate = useCallback(
|
||||
async (type) => {
|
||||
if (type === "unpin") {
|
||||
await sleep(1000);
|
||||
await Notifications.get();
|
||||
checkNotifPinned();
|
||||
}
|
||||
},
|
||||
[checkNotifPinned]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent("onUpdate", onUpdate);
|
||||
@@ -118,7 +122,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
return () => {
|
||||
eUnSubscribeEvent("onUpdate", onUpdate);
|
||||
};
|
||||
}, [item]);
|
||||
}, [item, onUpdate]);
|
||||
|
||||
function switchTheme() {
|
||||
toggleDarkMode();
|
||||
|
||||
@@ -62,6 +62,7 @@ import {
|
||||
} from "../services/event-manager";
|
||||
import { useEditorStore } from "../stores/use-editor-store";
|
||||
import { useDragState } from "../screens/settings/editor/state";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const SodiumEventEmitter = new NativeEventEmitter(NativeModules.Sodium);
|
||||
export const useAppEvents = () => {
|
||||
@@ -121,7 +122,7 @@ export const useAppEvents = () => {
|
||||
onRequestPartialSync
|
||||
);
|
||||
};
|
||||
}, [loading]);
|
||||
}, [loading, onSyncComplete]);
|
||||
|
||||
useEffect(() => {
|
||||
let subs = [
|
||||
@@ -156,10 +157,10 @@ export const useAppEvents = () => {
|
||||
|
||||
subs.forEach((sub) => sub?.remove());
|
||||
};
|
||||
}, []);
|
||||
}, [onEmailVerified, onSyncComplete, onUrlRecieved, onUserUpdated]);
|
||||
|
||||
const onSessionExpired = async () => {
|
||||
await SettingsService.set({
|
||||
SettingsService.set({
|
||||
sessionExpired: true
|
||||
});
|
||||
eSendEvent("session_expired");
|
||||
@@ -188,18 +189,26 @@ export const useAppEvents = () => {
|
||||
}
|
||||
return () => {
|
||||
refValues.current?.removeInternetStateListener &&
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
refValues.current?.removeInternetStateListener();
|
||||
sub?.remove();
|
||||
unsubIAP();
|
||||
};
|
||||
}, [loading, verify]);
|
||||
}, [
|
||||
loading,
|
||||
onAppStateChanged,
|
||||
onEmailVerified,
|
||||
onInternetStateChanged,
|
||||
onUserUpdated,
|
||||
verify
|
||||
]);
|
||||
|
||||
const onInternetStateChanged = async (state) => {
|
||||
const onInternetStateChanged = useCallback(async (state) => {
|
||||
if (!syncedOnLaunch.current) return;
|
||||
reconnectSSE(state);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onSyncComplete = async () => {
|
||||
const onSyncComplete = useCallback(async () => {
|
||||
console.log("sync complete");
|
||||
initAfterSync();
|
||||
setLastSynced(await db.lastSynced());
|
||||
@@ -209,22 +218,25 @@ export const useAppEvents = () => {
|
||||
if (note) {
|
||||
//await updateNoteInEditor();
|
||||
}
|
||||
};
|
||||
}, [setLastSynced]);
|
||||
|
||||
const onUrlRecieved = async (res) => {
|
||||
let url = res ? res.url : "";
|
||||
try {
|
||||
if (url.startsWith("https://app.notesnook.com/account/verified")) {
|
||||
await onEmailVerified();
|
||||
} else {
|
||||
return;
|
||||
const onUrlRecieved = useCallback(
|
||||
async (res) => {
|
||||
let url = res ? res.url : "";
|
||||
try {
|
||||
if (url.startsWith("https://app.notesnook.com/account/verified")) {
|
||||
await onEmailVerified();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
},
|
||||
[onEmailVerified]
|
||||
);
|
||||
|
||||
const onEmailVerified = async () => {
|
||||
const onEmailVerified = useCallback(async () => {
|
||||
let user = await db.user.getUser();
|
||||
setUser(user);
|
||||
if (!user) return;
|
||||
@@ -236,9 +248,9 @@ export const useAppEvents = () => {
|
||||
if (user?.isEmailConfirmed) {
|
||||
clearMessage();
|
||||
}
|
||||
};
|
||||
}, [setUser]);
|
||||
|
||||
const attachIAPListeners = async () => {
|
||||
const attachIAPListeners = useCallback(async () => {
|
||||
await RNIap.initConnection()
|
||||
.catch(() => null)
|
||||
.then(async () => {
|
||||
@@ -247,7 +259,7 @@ export const useAppEvents = () => {
|
||||
refValues.current.subsriptionErrorListener =
|
||||
RNIap.purchaseErrorListener(onSubscriptionError);
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onAccountStatusChange = async (userStatus) => {
|
||||
if (!PremiumService.get() && userStatus.type === 5) {
|
||||
@@ -281,59 +293,62 @@ export const useAppEvents = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const onUserUpdated = async (login) => {
|
||||
console.log(`onUserUpdated: ${login}`);
|
||||
let user;
|
||||
try {
|
||||
user = await db.user.getUser();
|
||||
await PremiumService.setPremiumStatus();
|
||||
setLastSynced(await db.lastSynced());
|
||||
await useDragState.getState().init();
|
||||
if (!user) {
|
||||
return setLoginMessage();
|
||||
}
|
||||
const onUserUpdated = useCallback(
|
||||
async (login) => {
|
||||
console.log(`onUserUpdated: ${login}`);
|
||||
let user;
|
||||
try {
|
||||
user = await db.user.getUser();
|
||||
await PremiumService.setPremiumStatus();
|
||||
setLastSynced(await db.lastSynced());
|
||||
await useDragState.getState().init();
|
||||
if (!user) {
|
||||
return setLoginMessage();
|
||||
}
|
||||
|
||||
let userEmailConfirmed = SettingsService.get().userEmailConfirmed;
|
||||
setUser(user);
|
||||
if (SettingsService.get().sessionExpired) {
|
||||
syncedOnLaunch.current = true;
|
||||
return;
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
attachIAPListeners();
|
||||
|
||||
if (!login) {
|
||||
user = await db.user.fetchUser();
|
||||
let userEmailConfirmed = SettingsService.get().userEmailConfirmed;
|
||||
setUser(user);
|
||||
if (SettingsService.get().sessionExpired) {
|
||||
syncedOnLaunch.current = true;
|
||||
return;
|
||||
}
|
||||
|
||||
clearMessage();
|
||||
attachIAPListeners();
|
||||
|
||||
if (!login) {
|
||||
user = await db.user.fetchUser();
|
||||
setUser(user);
|
||||
}
|
||||
|
||||
await PremiumService.setPremiumStatus();
|
||||
if (user?.isEmailConfirmed && !userEmailConfirmed) {
|
||||
setTimeout(() => {
|
||||
onEmailVerified();
|
||||
}, 1000);
|
||||
SettingsService.set({
|
||||
userEmailConfirmed: true
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
ToastEvent.error(e, "An error occured", "global");
|
||||
}
|
||||
|
||||
await PremiumService.setPremiumStatus();
|
||||
if (user?.isEmailConfirmed && !userEmailConfirmed) {
|
||||
setTimeout(() => {
|
||||
onEmailVerified();
|
||||
}, 1000);
|
||||
SettingsService.set({
|
||||
userEmailConfirmed: true
|
||||
});
|
||||
user = await db.user.getUser();
|
||||
if (
|
||||
user?.isEmailConfirmed &&
|
||||
!SettingsService.get().recoveryKeySaved &&
|
||||
!useMessageStore.getState().message?.visible
|
||||
) {
|
||||
setRecoveryKeyMessage();
|
||||
}
|
||||
} catch (e) {
|
||||
ToastEvent.error(e, "An error occured", "global");
|
||||
}
|
||||
if (!user?.isEmailConfirmed) setEmailVerifyMessage();
|
||||
refValues.current.isUserReady = true;
|
||||
|
||||
user = await db.user.getUser();
|
||||
if (
|
||||
user?.isEmailConfirmed &&
|
||||
!SettingsService.get().recoveryKeySaved &&
|
||||
!useMessageStore.getState().message?.visible
|
||||
) {
|
||||
setRecoveryKeyMessage();
|
||||
}
|
||||
if (!user?.isEmailConfirmed) setEmailVerifyMessage();
|
||||
refValues.current.isUserReady = true;
|
||||
|
||||
syncedOnLaunch.current = true;
|
||||
};
|
||||
syncedOnLaunch.current = true;
|
||||
},
|
||||
[attachIAPListeners, onEmailVerified, setLastSynced, setUser]
|
||||
);
|
||||
|
||||
const onSuccessfulSubscription = async (subscription) => {
|
||||
await PremiumService.subscriptions.set(subscription);
|
||||
@@ -349,59 +364,65 @@ export const useAppEvents = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const onAppStateChanged = async (state) => {
|
||||
console.log("onAppStateChanged");
|
||||
if (state === "active") {
|
||||
updateStatusBarColor();
|
||||
if (
|
||||
SettingsService.get().appLockMode !== "background" &&
|
||||
!SettingsService.get().privacyScreen
|
||||
) {
|
||||
enabled(false);
|
||||
}
|
||||
if (SettingsService.get().appLockMode === "background") {
|
||||
if (useSettingStore.getState().requestBiometrics) {
|
||||
useSettingStore.getState().setRequestBiometrics(false);
|
||||
return;
|
||||
const onAppStateChanged = useCallback(
|
||||
async (state) => {
|
||||
console.log("onAppStateChanged");
|
||||
if (state === "active") {
|
||||
updateStatusBarColor();
|
||||
if (
|
||||
SettingsService.get().appLockMode !== "background" &&
|
||||
!SettingsService.get().privacyScreen
|
||||
) {
|
||||
enabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
await reconnectSSE();
|
||||
await checkIntentState();
|
||||
MMKV.removeItem("appState");
|
||||
let user = await db.user.getUser();
|
||||
if (user && !user?.isEmailConfirmed) {
|
||||
try {
|
||||
let user = await db.user.fetchUser();
|
||||
if (user?.isEmailConfirmed) {
|
||||
onEmailVerified();
|
||||
if (SettingsService.get().appLockMode === "background") {
|
||||
if (useSettingStore.getState().requestBiometrics) {
|
||||
useSettingStore.getState().setRequestBiometrics(false);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
await reconnectSSE();
|
||||
await checkIntentState();
|
||||
MMKV.removeItem("appState");
|
||||
let user = await db.user.getUser();
|
||||
if (user && !user?.isEmailConfirmed) {
|
||||
try {
|
||||
let user = await db.user.fetchUser();
|
||||
if (user?.isEmailConfirmed) {
|
||||
onEmailVerified();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let id = useEditorStore.getState().currentEditingNote;
|
||||
let note = id && db.notes.note(id).data;
|
||||
if (
|
||||
note?.locked &&
|
||||
SettingsService.get().appLockMode === "background"
|
||||
) {
|
||||
eSendEvent(eClearEditor);
|
||||
}
|
||||
await storeAppState();
|
||||
if (
|
||||
SettingsService.get().appLockMode === "background" &&
|
||||
!useSettingStore.getState().requestBiometrics &&
|
||||
!useUserStore.getState().verifyUser
|
||||
) {
|
||||
useUserStore.getState().setVerifyUser(true);
|
||||
}
|
||||
if (
|
||||
SettingsService.get().privacyScreen ||
|
||||
SettingsService.get().appLockMode === "background"
|
||||
) {
|
||||
!useSettingStore.getState().requestBiometrics ? enabled(true) : null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let id = useEditorStore.getState().currentEditingNote;
|
||||
let note = id && db.notes.note(id).data;
|
||||
if (note?.locked && SettingsService.get().appLockMode === "background") {
|
||||
eSendEvent(eClearEditor);
|
||||
}
|
||||
await storeAppState();
|
||||
if (
|
||||
SettingsService.get().appLockMode === "background" &&
|
||||
!useSettingStore.getState().requestBiometrics &&
|
||||
!useUserStore.getState().verifyUser
|
||||
) {
|
||||
useUserStore.getState().setVerifyUser(true);
|
||||
}
|
||||
if (
|
||||
SettingsService.get().privacyScreen ||
|
||||
SettingsService.get().appLockMode === "background"
|
||||
) {
|
||||
!useSettingStore.getState().requestBiometrics ? enabled(true) : null;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
[onEmailVerified]
|
||||
);
|
||||
|
||||
async function reconnectSSE(connection) {
|
||||
if (refValues.current?.isReconnecting) return;
|
||||
|
||||
@@ -46,7 +46,7 @@ export const useAttachmentProgress = (attachment, encryption) => {
|
||||
} else {
|
||||
setCurrentProgress(null);
|
||||
}
|
||||
}, [progress]);
|
||||
}, [attachment.metadata.hash, progress]);
|
||||
|
||||
return [currentProgress, setCurrentProgress];
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@ import { useEditorStore } from "../stores/use-editor-store";
|
||||
import { useTagStore } from "../stores/use-tag-store";
|
||||
import { db } from "../common/database";
|
||||
import { NoteType } from "app/utils/types";
|
||||
import { useCallback } from "react";
|
||||
|
||||
/**
|
||||
* A hook that injects/removes tags from tags bar in editor
|
||||
@@ -34,7 +35,7 @@ const useEditorTags = () => {
|
||||
const [note, setNote] = useState<NoteType | null>(null);
|
||||
const [noteTags, setNoteTags] = useState<string[]>([]);
|
||||
|
||||
async function refreshNote() {
|
||||
const refreshNote = useCallback(() => {
|
||||
const current = useEditorStore.getState().currentEditingNote;
|
||||
if (!current) {
|
||||
setNote(null);
|
||||
@@ -44,23 +45,23 @@ const useEditorTags = () => {
|
||||
const note = db.notes?.note(current)?.data as NoteType;
|
||||
setNote(note ? { ...note } : null);
|
||||
getTags(note);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refreshNote();
|
||||
}, [currentEditingNote, tags]);
|
||||
}, [currentEditingNote, refreshNote, tags]);
|
||||
|
||||
function load() {
|
||||
const load = useCallback(() => {
|
||||
if (!note) return;
|
||||
// tiny.call(EditorWebView, renderTags(noteTags));
|
||||
}
|
||||
}, [note]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent("updateTags", load);
|
||||
return () => {
|
||||
eUnSubscribeEvent("updateTags", load);
|
||||
};
|
||||
}, [noteTags]);
|
||||
}, [load, noteTags]);
|
||||
|
||||
function getTags(note: NoteType) {
|
||||
if (!note || !note.tags) return [];
|
||||
@@ -72,7 +73,7 @@ const useEditorTags = () => {
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, [noteTags]);
|
||||
}, [load, noteTags]);
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
@@ -25,7 +25,9 @@ const useImmediateEffect = (callback: EffectCallback, deps: DependencyList) => {
|
||||
cleanup = callback();
|
||||
});
|
||||
return cleanup;
|
||||
}, deps);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [callback, ...deps]);
|
||||
};
|
||||
|
||||
export default useImmediateEffect;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Keyboard, KeyboardEvent, useWindowDimensions } from "react-native";
|
||||
import { useCallback } from "react";
|
||||
|
||||
/**
|
||||
* A hook that detects floating keyboard on iPad
|
||||
@@ -28,9 +29,12 @@ const useIsFloatingKeyboard = () => {
|
||||
|
||||
const [floating, setFloating] = useState<boolean>(false);
|
||||
|
||||
const onKeyboardWillChangeFrame = (event: KeyboardEvent) => {
|
||||
setFloating(event.endCoordinates.width !== width);
|
||||
};
|
||||
const onKeyboardWillChangeFrame = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
setFloating(event.endCoordinates.width !== width);
|
||||
},
|
||||
[width]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const sub1 = Keyboard.addListener(
|
||||
@@ -40,7 +44,7 @@ const useIsFloatingKeyboard = () => {
|
||||
return () => {
|
||||
sub1?.remove();
|
||||
};
|
||||
}, [width]);
|
||||
}, [onKeyboardWillChangeFrame, width]);
|
||||
|
||||
return floating;
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ export const useNavigationFocus = (
|
||||
},
|
||||
isBlurred.current ? 0 : delay || 300
|
||||
);
|
||||
}, [onFocus, prev]);
|
||||
}, [delay, onFocus]);
|
||||
|
||||
const _onBlur = useCallback(() => {
|
||||
isBlurred.current = true;
|
||||
@@ -58,7 +58,7 @@ export const useNavigationFocus = (
|
||||
setFocused(false);
|
||||
}
|
||||
}, delay || 300);
|
||||
}, [onBlur, prev]);
|
||||
}, [delay, onBlur]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!navigation) return;
|
||||
@@ -69,7 +69,7 @@ export const useNavigationFocus = (
|
||||
return () => {
|
||||
subs.forEach((sub) => sub());
|
||||
};
|
||||
}, [navigation]);
|
||||
}, [_onBlur, _onFocus, navigation]);
|
||||
|
||||
return isFocused;
|
||||
};
|
||||
|
||||
@@ -23,7 +23,6 @@ import { useEffect, useRef, useState } from "react";
|
||||
* It will return random item in an array after given interval
|
||||
*/
|
||||
function useRotator<T>(data: T[], interval = 3000): T | null {
|
||||
if (!Array.isArray(data)) return null;
|
||||
//@ts-ignore Added sample() method to Array.prototype to get random value.
|
||||
const [current, setCurrent] = useState<T>(data.sample());
|
||||
const intervalRef = useRef<NodeJS.Timer>();
|
||||
@@ -39,7 +38,7 @@ function useRotator<T>(data: T[], interval = 3000): T | null {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
};
|
||||
});
|
||||
}, [data, interval]);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ const useSyncProgress = () => {
|
||||
EV?.unsubscribe(EVENTS.syncProgress, onProgress);
|
||||
EV?.unsubscribe(EVENTS.syncCompleted, onSyncComplete);
|
||||
};
|
||||
}, []);
|
||||
}, [EV, onProgress]);
|
||||
|
||||
return {
|
||||
progress
|
||||
|
||||
@@ -113,7 +113,7 @@ export const useTooltipHandler = (
|
||||
return () => {
|
||||
eUnSubscribeEvent(id, callback);
|
||||
};
|
||||
}, []);
|
||||
}, [callback, id]);
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export const useVaultStatus = () => {
|
||||
return () => {
|
||||
eUnSubscribeEvent("vaultUpdated", () => checkVaultStatus());
|
||||
};
|
||||
}, []);
|
||||
}, [checkVaultStatus]);
|
||||
|
||||
return vaultStatus;
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ export const useVaultStatus = () => {
|
||||
return () => {
|
||||
eUnSubscribeEvent("vaultUpdated", () => checkVaultStatus());
|
||||
};
|
||||
}, []);
|
||||
}, [checkVaultStatus]);
|
||||
|
||||
return vaultStatus;
|
||||
};
|
||||
|
||||
@@ -89,7 +89,7 @@ const _Tabs = () => {
|
||||
setTimeout(() => {
|
||||
useNavigationStore.getState().update({ name: homepage });
|
||||
}, 1000);
|
||||
}, []);
|
||||
}, [homepage]);
|
||||
|
||||
return (
|
||||
<NativeStack.Navigator
|
||||
@@ -169,7 +169,7 @@ const _NavigationStack = () => {
|
||||
}
|
||||
hideAllTooltips();
|
||||
eSendEvent("navigate");
|
||||
});
|
||||
}, [clearSelection]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
|
||||
@@ -59,6 +59,7 @@ import {
|
||||
import { editorRef, tabBarRef } from "../utils/global-refs";
|
||||
import { hideAllTooltips } from "../hooks/use-tooltip";
|
||||
import { NavigationStack } from "./navigation-stack";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const _TabsHolder = () => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -92,7 +93,7 @@ const _TabsHolder = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const showFullScreenEditor = () => {
|
||||
const showFullScreenEditor = useCallback(() => {
|
||||
setFullscreen(true);
|
||||
if (deviceMode === "smallTablet") {
|
||||
tabBarRef.current?.openDrawer();
|
||||
@@ -107,9 +108,9 @@ const _TabsHolder = () => {
|
||||
: dimensions.width * 0.15
|
||||
}
|
||||
});
|
||||
};
|
||||
}, [deviceMode, dimensions.width, setFullscreen]);
|
||||
|
||||
const closeFullScreenEditor = () => {
|
||||
const closeFullScreenEditor = useCallback(() => {
|
||||
if (deviceMode === "smallTablet") {
|
||||
tabBarRef.current?.closeDrawer();
|
||||
}
|
||||
@@ -132,7 +133,7 @@ const _TabsHolder = () => {
|
||||
tabBarRef.current?.goToIndex(1);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
}, [deviceMode, dimensions.width, setFullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!tabBarRef.current?.isDrawerOpen()) {
|
||||
@@ -145,7 +146,14 @@ const _TabsHolder = () => {
|
||||
eUnSubscribeEvent(eOpenFullscreenEditor, showFullScreenEditor);
|
||||
eUnSubscribeEvent(eCloseFullscreenEditor, closeFullScreenEditor);
|
||||
};
|
||||
}, [deviceMode, dimensions, colors]);
|
||||
}, [
|
||||
deviceMode,
|
||||
dimensions,
|
||||
colors,
|
||||
showFullScreenEditor,
|
||||
closeFullScreenEditor,
|
||||
toggleView
|
||||
]);
|
||||
|
||||
const _onLayout = async (event) => {
|
||||
console.log("layout called here");
|
||||
@@ -259,9 +267,12 @@ const _TabsHolder = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const toggleView = (show) => {
|
||||
animatedTranslateY.value = show ? 0 : -9999;
|
||||
};
|
||||
const toggleView = useCallback(
|
||||
(show) => {
|
||||
animatedTranslateY.value = show ? 0 : -9999;
|
||||
},
|
||||
[animatedTranslateY]
|
||||
);
|
||||
|
||||
const valueLimiter = (value, min, max) => {
|
||||
if (value < min) {
|
||||
|
||||
@@ -42,6 +42,7 @@ import { EditorProps, useEditorType } from "./tiptap/types";
|
||||
import { useEditor } from "./tiptap/use-editor";
|
||||
import { useEditorEvents } from "./tiptap/use-editor-events";
|
||||
import { editorController } from "./tiptap/utils";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const style: ViewStyle = {
|
||||
height: "100%",
|
||||
@@ -91,23 +92,32 @@ const Editor = React.memo(
|
||||
get: () => editor
|
||||
}));
|
||||
|
||||
const onMediaDownloaded = ({
|
||||
hash,
|
||||
groupId,
|
||||
src
|
||||
}: {
|
||||
hash: string;
|
||||
groupId: string;
|
||||
src: string;
|
||||
}) => {
|
||||
console.log("onMediaDownoaded", groupId);
|
||||
const onMediaDownloaded = useCallback(
|
||||
({
|
||||
hash,
|
||||
groupId,
|
||||
src
|
||||
}: {
|
||||
hash: string;
|
||||
groupId: string;
|
||||
src: string;
|
||||
}) => {
|
||||
console.log("onMediaDownoaded", groupId);
|
||||
|
||||
if (groupId !== editor.note.current?.id) return;
|
||||
editor.commands.updateImage({
|
||||
hash: hash,
|
||||
src: src
|
||||
});
|
||||
};
|
||||
if (groupId !== editor.note.current?.id) return;
|
||||
editor.commands.updateImage({
|
||||
hash: hash,
|
||||
src: src
|
||||
});
|
||||
},
|
||||
[editor.commands, editor.note]
|
||||
);
|
||||
|
||||
const onError = useCallback(() => {
|
||||
console.log("RENDER PROCESS GONE!!!");
|
||||
editor.setLoading(true);
|
||||
setTimeout(() => editor.setLoading(false), 10);
|
||||
}, [editor]);
|
||||
|
||||
useEffect(() => {
|
||||
onLoad && onLoad();
|
||||
@@ -117,17 +127,12 @@ const Editor = React.memo(
|
||||
eUnSubscribeEvent("webview_reset", onError);
|
||||
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
|
||||
};
|
||||
}, []);
|
||||
}, [onError, onLoad, onMediaDownloaded]);
|
||||
|
||||
if (withController) {
|
||||
editorController.current = editor;
|
||||
}
|
||||
|
||||
const onError = () => {
|
||||
console.log("RENDER PROCESS GONE!!!");
|
||||
editor.setLoading(true);
|
||||
setTimeout(() => editor.setLoading(false), 10);
|
||||
};
|
||||
console.log(editor.loading, "loading editor");
|
||||
return editor.loading ? null : (
|
||||
<>
|
||||
|
||||
@@ -36,6 +36,7 @@ import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { eClearEditor, eOnLoadNote } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { editorState } from "./tiptap/utils";
|
||||
import { useCallback } from "react";
|
||||
const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [error, setError] = useState(false);
|
||||
@@ -55,34 +56,37 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
clearTimeout(timers.current.closing);
|
||||
};
|
||||
|
||||
const load = async (_loading) => {
|
||||
editorState().overlay = true;
|
||||
clearTimers();
|
||||
if (_loading) {
|
||||
opacity.value = 1;
|
||||
translateValue.value = 0;
|
||||
timers.current.error = setTimeout(() => {
|
||||
if (_loading) {
|
||||
let note = _loading;
|
||||
note.forced = true;
|
||||
eSendEvent(eOnLoadNote + editorId, note);
|
||||
}
|
||||
setError(true);
|
||||
}, 4000);
|
||||
} else {
|
||||
const load = useCallback(
|
||||
async (_loading) => {
|
||||
editorState().overlay = true;
|
||||
clearTimers();
|
||||
setTimeout(() => {
|
||||
setError(false);
|
||||
editorState().overlay = false;
|
||||
opacity.value = withTiming(0, {
|
||||
duration: 500
|
||||
});
|
||||
if (_loading) {
|
||||
opacity.value = 1;
|
||||
translateValue.value = 0;
|
||||
timers.current.error = setTimeout(() => {
|
||||
if (_loading) {
|
||||
let note = _loading;
|
||||
note.forced = true;
|
||||
eSendEvent(eOnLoadNote + editorId, note);
|
||||
}
|
||||
setError(true);
|
||||
}, 4000);
|
||||
} else {
|
||||
clearTimers();
|
||||
setTimeout(() => {
|
||||
translateValue.value = 6000;
|
||||
}, 500);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
setError(false);
|
||||
editorState().overlay = false;
|
||||
opacity.value = withTiming(0, {
|
||||
duration: 500
|
||||
});
|
||||
setTimeout(() => {
|
||||
translateValue.value = 6000;
|
||||
}, 500);
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
[editorId, opacity, translateValue]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent("loadingNote" + editorId, load);
|
||||
@@ -90,7 +94,7 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
clearTimers();
|
||||
eUnSubscribeEvent("loadingNote" + editorId, load);
|
||||
};
|
||||
}, [editorId]);
|
||||
}, [editorId, load]);
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
|
||||
@@ -151,10 +151,8 @@ export const useEditorEvents = (
|
||||
);
|
||||
const tools = useDragState((state) => state.data);
|
||||
const { keyboardShown } = useKeyboard();
|
||||
if (!editor) return null;
|
||||
|
||||
useEffect(() => {
|
||||
console.log("keyboardShown", keyboardShown);
|
||||
editor.commands.setSettings({
|
||||
deviceMode: deviceMode || "mobile",
|
||||
fullscreen: fullscreen || false,
|
||||
@@ -176,7 +174,10 @@ export const useEditorEvents = (
|
||||
tools,
|
||||
editor.commands,
|
||||
keyboardShown,
|
||||
doubleSpacedLines
|
||||
doubleSpacedLines,
|
||||
editorPropReadonly,
|
||||
noHeader,
|
||||
noToolbar
|
||||
]);
|
||||
|
||||
const onBackPress = useCallback(async () => {
|
||||
@@ -211,14 +212,14 @@ export const useEditorEvents = (
|
||||
editorState().currentlyEditing = false;
|
||||
editor.reset();
|
||||
}, 1);
|
||||
}, [fullscreen, deviceMode]);
|
||||
}, [editor, deviceMode, fullscreen]);
|
||||
|
||||
const onHardwareBackPress = useCallback(() => {
|
||||
if (editorState().currentlyEditing) {
|
||||
onBackPress();
|
||||
return true;
|
||||
}
|
||||
}, []);
|
||||
}, [onBackPress]);
|
||||
|
||||
const onLoadNote = useCallback(async () => {
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
@@ -229,29 +230,32 @@ export const useEditorEvents = (
|
||||
);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
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();
|
||||
}, [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();
|
||||
}
|
||||
}, []);
|
||||
handleBack.current = BackHandler.addEventListener(
|
||||
"hardwareBackPress",
|
||||
onHardwareBackPress
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (editorState().currentlyEditing) {
|
||||
await onBackPress();
|
||||
}
|
||||
},
|
||||
[onBackPress, onHardwareBackPress]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (fullscreen && DDS.isTab) {
|
||||
@@ -266,7 +270,7 @@ export const useEditorEvents = (
|
||||
handleBack.current.remove();
|
||||
}
|
||||
};
|
||||
}, [fullscreen]);
|
||||
}, [fullscreen, onHardwareBackPress]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOnLoadNote + editor.editorId, onLoadNote);
|
||||
@@ -275,107 +279,110 @@ export const useEditorEvents = (
|
||||
eUnSubscribeEvent(eClearEditor, onCallClear);
|
||||
eUnSubscribeEvent(eOnLoadNote, onLoadNote);
|
||||
};
|
||||
}, []);
|
||||
}, [editor.editorId, onCallClear, onLoadNote]);
|
||||
|
||||
const onMessage = (event: WebViewMessageEvent) => {
|
||||
const data = event.nativeEvent.data;
|
||||
const editorMessage = JSON.parse(data) as EditorMessage;
|
||||
const onMessage = useCallback(
|
||||
(event: WebViewMessageEvent) => {
|
||||
const data = event.nativeEvent.data;
|
||||
const 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 as string
|
||||
});
|
||||
break;
|
||||
case EventTypes.selection:
|
||||
break;
|
||||
case EventTypes.title:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value as string
|
||||
});
|
||||
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
|
||||
?.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:
|
||||
const { pick } = require("./picker.js").default;
|
||||
pick({ type: editorMessage.value });
|
||||
break;
|
||||
case EventTypes.download:
|
||||
console.log("download attachment request", editorMessage.value);
|
||||
const attachmentInfo = editorMessage.value as Attachment;
|
||||
filesystem.downloadAttachment(attachmentInfo?.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(editor);
|
||||
break;
|
||||
case EventTypes.properties:
|
||||
showActionsheet(editor);
|
||||
break;
|
||||
case EventTypes.fullscreen:
|
||||
editorState().isFullscreen = true;
|
||||
eSendEvent(eOpenFullscreenEditor);
|
||||
break;
|
||||
case EventTypes.back:
|
||||
onBackPress();
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
"unhandled event recieved from editor: ",
|
||||
logger.info("editor", editorMessage.type);
|
||||
if (
|
||||
editorMessage.sessionId !== editor.sessionId &&
|
||||
editorMessage.type !== EditorEvents.status
|
||||
) {
|
||||
logger.error(
|
||||
"editor",
|
||||
"invalid session",
|
||||
editorMessage.type,
|
||||
editorMessage.value
|
||||
editor.sessionId,
|
||||
editorMessage.sessionId
|
||||
);
|
||||
break;
|
||||
}
|
||||
eSendEvent(editorMessage.type, editorMessage);
|
||||
};
|
||||
|
||||
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 as string
|
||||
});
|
||||
break;
|
||||
case EventTypes.selection:
|
||||
break;
|
||||
case EventTypes.title:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value as string
|
||||
});
|
||||
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
|
||||
?.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:
|
||||
const { pick } = require("./picker.js").default;
|
||||
pick({ type: editorMessage.value });
|
||||
break;
|
||||
case EventTypes.download:
|
||||
console.log("download attachment request", editorMessage.value);
|
||||
const attachmentInfo = editorMessage.value as Attachment;
|
||||
filesystem.downloadAttachment(attachmentInfo?.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(editor);
|
||||
break;
|
||||
case EventTypes.properties:
|
||||
showActionsheet(editor);
|
||||
break;
|
||||
case EventTypes.fullscreen:
|
||||
editorState().isFullscreen = true;
|
||||
eSendEvent(eOpenFullscreenEditor);
|
||||
break;
|
||||
case EventTypes.back:
|
||||
onBackPress();
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
"unhandled event recieved from editor: ",
|
||||
editorMessage.type,
|
||||
editorMessage.value
|
||||
);
|
||||
break;
|
||||
}
|
||||
eSendEvent(editorMessage.type, editorMessage);
|
||||
},
|
||||
[editor, onBackPress]
|
||||
);
|
||||
|
||||
return onMessage;
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@ export const useEditor = (
|
||||
commands.setInsets(
|
||||
isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 }
|
||||
);
|
||||
}, [insets]);
|
||||
}, [commands, insets, isDefaultEditor]);
|
||||
|
||||
useEffect(() => {
|
||||
sessionIdRef.current = sessionId;
|
||||
@@ -87,7 +87,7 @@ export const useEditor = (
|
||||
|
||||
useEffect(() => {
|
||||
commands.setTags(currentNote.current);
|
||||
}, [tags]);
|
||||
}, [commands, tags]);
|
||||
|
||||
useEffect(() => {
|
||||
if (theme) return;
|
||||
@@ -98,28 +98,17 @@ export const useEditor = (
|
||||
return () => {
|
||||
unsub();
|
||||
};
|
||||
}, []);
|
||||
}, [postMessage, theme]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("sessionId:", sessionId);
|
||||
async () => {
|
||||
await commands.setSessionId(sessionIdRef.current);
|
||||
if (sessionIdRef.current) {
|
||||
if (!state.current?.ready) return;
|
||||
await onReady();
|
||||
}
|
||||
};
|
||||
return () => {
|
||||
state.current.saveCount = 0;
|
||||
};
|
||||
}, [sessionId, loading]);
|
||||
|
||||
const overlay = (show: boolean, data = { type: "new" }) => {
|
||||
eSendEvent(
|
||||
"loadingNote" + editorId,
|
||||
show ? currentNote.current || data : false
|
||||
);
|
||||
};
|
||||
const overlay = useCallback(
|
||||
(show: boolean, data = { type: "new" }) => {
|
||||
eSendEvent(
|
||||
"loadingNote" + editorId,
|
||||
show ? currentNote.current || data : false
|
||||
);
|
||||
},
|
||||
[editorId]
|
||||
);
|
||||
|
||||
const onReady = useCallback(async () => {
|
||||
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
|
||||
@@ -127,7 +116,19 @@ export const useEditor = (
|
||||
overlay(true);
|
||||
setLoading(true);
|
||||
}
|
||||
}, []);
|
||||
}, [overlay]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("sessionId:", sessionId);
|
||||
state.current.saveCount = 0;
|
||||
async () => {
|
||||
await commands.setSessionId(sessionIdRef.current);
|
||||
if (sessionIdRef.current) {
|
||||
if (!state.current?.ready) return;
|
||||
await onReady();
|
||||
}
|
||||
};
|
||||
}, [sessionId, loading, commands, onReady]);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
@@ -143,24 +144,27 @@ export const useEditor = (
|
||||
[]
|
||||
);
|
||||
|
||||
const reset = useCallback(async (resetState = true) => {
|
||||
currentNote.current?.id && db.fs.cancel(currentNote.current.id);
|
||||
currentNote.current = null;
|
||||
currentContent.current = null;
|
||||
sessionHistoryId.current = undefined;
|
||||
saveCount.current = 0;
|
||||
useEditorStore.getState().setReadonly(false);
|
||||
postMessage(EditorEvents.title, "");
|
||||
await commands.clearContent();
|
||||
await commands.clearTags();
|
||||
console.log("reset state: ", resetState);
|
||||
if (resetState) {
|
||||
isDefaultEditor &&
|
||||
useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
placeholderTip.current = TipManager.placeholderTip();
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
}
|
||||
}, []);
|
||||
const reset = useCallback(
|
||||
async (resetState = true) => {
|
||||
currentNote.current?.id && db.fs.cancel(currentNote.current.id);
|
||||
currentNote.current = null;
|
||||
currentContent.current = null;
|
||||
sessionHistoryId.current = undefined;
|
||||
saveCount.current = 0;
|
||||
useEditorStore.getState().setReadonly(false);
|
||||
postMessage(EditorEvents.title, "");
|
||||
await commands.clearContent();
|
||||
await commands.clearTags();
|
||||
console.log("reset state: ", resetState);
|
||||
if (resetState) {
|
||||
isDefaultEditor &&
|
||||
useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
placeholderTip.current = TipManager.placeholderTip();
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
}
|
||||
},
|
||||
[commands, isDefaultEditor, postMessage]
|
||||
);
|
||||
|
||||
const saveNote = useCallback(
|
||||
async ({
|
||||
@@ -236,6 +240,7 @@ export const useEditor = (
|
||||
}
|
||||
} else {
|
||||
noteData.contentId = note?.contentId;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
await db.vault?.save(noteData as any);
|
||||
}
|
||||
console.log(id, sessionIdRef.current, currentSessionId);
|
||||
@@ -265,7 +270,7 @@ export const useEditor = (
|
||||
console.log("error saving: ", e);
|
||||
}
|
||||
},
|
||||
[commands, reset]
|
||||
[commands, isDefaultEditor, postMessage, readonly, reset]
|
||||
);
|
||||
|
||||
const loadContent = useCallback(async (note: NoteType) => {
|
||||
@@ -322,7 +327,15 @@ export const useEditor = (
|
||||
loadImages();
|
||||
}
|
||||
},
|
||||
[setSessionId]
|
||||
[
|
||||
commands,
|
||||
editorId,
|
||||
isDefaultEditor,
|
||||
loadContent,
|
||||
overlay,
|
||||
postMessage,
|
||||
reset
|
||||
]
|
||||
);
|
||||
|
||||
const loadImages = () => {
|
||||
@@ -352,7 +365,7 @@ export const useEditor = (
|
||||
return () => {
|
||||
eUnSubscribeEvent(eOnLoadNote + editorId, loadNote);
|
||||
};
|
||||
}, [editorId]);
|
||||
}, [editorId, loadNote]);
|
||||
|
||||
const saveContent = useCallback(
|
||||
({
|
||||
@@ -398,28 +411,10 @@ export const useEditor = (
|
||||
500
|
||||
);
|
||||
},
|
||||
[sessionIdRef, sessionId]
|
||||
[sessionId, withTimer, onChange, saveNote]
|
||||
);
|
||||
|
||||
const onLoad = useCallback(async () => {
|
||||
console.log("on editor load");
|
||||
state.current.ready = true;
|
||||
onReady();
|
||||
postMessage(EditorEvents.theme, theme || useThemeStore.getState().colors);
|
||||
commands.setInsets(
|
||||
isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 }
|
||||
);
|
||||
if (currentNote.current) {
|
||||
console.log("force reload note");
|
||||
loadNote({ ...currentNote.current, forced: true });
|
||||
} else {
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
isDefaultEditor && restoreEditorState();
|
||||
}
|
||||
commands.setSettings();
|
||||
}, [state, currentNote, loadNote]);
|
||||
|
||||
async function restoreEditorState() {
|
||||
const restoreEditorState = useCallback(async () => {
|
||||
const json = await MMKV.getItem("appState");
|
||||
if (json) {
|
||||
const appState = JSON.parse(json) as AppState;
|
||||
@@ -451,7 +446,34 @@ export const useEditor = (
|
||||
return;
|
||||
}
|
||||
state.current.isRestoringState = false;
|
||||
}
|
||||
}, [loadNote, overlay]);
|
||||
|
||||
const onLoad = useCallback(async () => {
|
||||
console.log("on editor load");
|
||||
state.current.ready = true;
|
||||
onReady();
|
||||
postMessage(EditorEvents.theme, theme || useThemeStore.getState().colors);
|
||||
commands.setInsets(
|
||||
isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 }
|
||||
);
|
||||
if (currentNote.current) {
|
||||
console.log("force reload note");
|
||||
loadNote({ ...currentNote.current, forced: true });
|
||||
} else {
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
isDefaultEditor && restoreEditorState();
|
||||
}
|
||||
commands.setSettings();
|
||||
}, [
|
||||
onReady,
|
||||
postMessage,
|
||||
theme,
|
||||
commands,
|
||||
isDefaultEditor,
|
||||
insets,
|
||||
loadNote,
|
||||
restoreEditorState
|
||||
]);
|
||||
|
||||
return {
|
||||
ref: editorRef,
|
||||
|
||||
@@ -30,12 +30,11 @@ import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import Navigation, {
|
||||
NavigationProps,
|
||||
NotebookScreenParams
|
||||
} from "../../services/navigation";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SearchService from "../../services/search";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import useNavigationStore, {
|
||||
NotebookScreenParams
|
||||
} from "../../stores/use-navigation-store";
|
||||
import {
|
||||
eOnNewTopicAdded,
|
||||
eOpenAddNotebookDialog,
|
||||
@@ -60,7 +59,7 @@ const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
onBlur: () => false
|
||||
});
|
||||
|
||||
const syncWithNavigation = () => {
|
||||
const syncWithNavigation = React.useCallback(() => {
|
||||
useNavigationStore.getState().update(
|
||||
{
|
||||
name: route.name,
|
||||
@@ -71,35 +70,38 @@ const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
params.current?.canGoBack
|
||||
);
|
||||
SearchService.prepareSearch = prepareSearch;
|
||||
};
|
||||
}, [route.name]);
|
||||
|
||||
const onRequestUpdate = (data?: NotebookScreenParams) => {
|
||||
if (data) params.current = data;
|
||||
params.current.title = params.current.item.title;
|
||||
try {
|
||||
const notebook = db.notebooks?.notebook(params?.current?.item?.id)
|
||||
?.data as NotebookType;
|
||||
if (notebook) {
|
||||
params.current.item = notebook;
|
||||
setTopics(
|
||||
groupArray(
|
||||
qclone(notebook.topics),
|
||||
db.settings?.getGroupOptions("topics")
|
||||
)
|
||||
);
|
||||
syncWithNavigation();
|
||||
const onRequestUpdate = React.useCallback(
|
||||
(data?: NotebookScreenParams) => {
|
||||
if (data) params.current = data;
|
||||
params.current.title = params.current.item.title;
|
||||
try {
|
||||
const notebook = db.notebooks?.notebook(params?.current?.item?.id)
|
||||
?.data as NotebookType;
|
||||
if (notebook) {
|
||||
params.current.item = notebook;
|
||||
setTopics(
|
||||
groupArray(
|
||||
qclone(notebook.topics),
|
||||
db.settings?.getGroupOptions("topics")
|
||||
)
|
||||
);
|
||||
syncWithNavigation();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
},
|
||||
[syncWithNavigation]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOnNewTopicAdded, onRequestUpdate);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eOnNewTopicAdded, onRequestUpdate);
|
||||
};
|
||||
}, [topics]);
|
||||
}, [onRequestUpdate, topics]);
|
||||
|
||||
const prepareSearch = () => {
|
||||
SearchService.update({
|
||||
|
||||
@@ -20,10 +20,8 @@ import { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import React from "react";
|
||||
import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
import Navigation, {
|
||||
NavigationProps,
|
||||
NotesScreenParams
|
||||
} from "../../services/navigation";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import { NotesScreenParams } from "../../stores/use-navigation-store";
|
||||
import { ColorType } from "../../utils/types";
|
||||
import { getAlias, openEditor, toCamelCase } from "./common";
|
||||
export const ColoredNotes = ({
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import Navigation, { NotesScreenParams } from "../../services/navigation";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useMenuStore } from "../../stores/use-menu-store";
|
||||
import { useTagStore } from "../../stores/use-tag-store";
|
||||
import { db } from "../../common/database";
|
||||
@@ -26,6 +26,8 @@ import { eOnLoadNote } from "../../utils/events";
|
||||
import { openLinkInBrowser } from "../../utils/functions";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { editorController, editorState } from "../editor/tiptap/utils";
|
||||
import { NotesScreenParams } from "../../stores/use-navigation-store";
|
||||
import { TopicType } from "../../utils/types";
|
||||
|
||||
export function toCamelCase(title: string) {
|
||||
return title.slice(0, 1).toUpperCase() + title.slice(1);
|
||||
@@ -34,7 +36,7 @@ export function toCamelCase(title: string) {
|
||||
export function getAlias(params: Partial<NotesScreenParams>) {
|
||||
if (!params) return "";
|
||||
const { item } = params;
|
||||
return item?.alias || item?.title;
|
||||
return (item as TopicType)?.alias || item?.title;
|
||||
}
|
||||
|
||||
export function openMonographsWebpage() {
|
||||
|
||||
@@ -25,13 +25,11 @@ import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import Navigation, {
|
||||
NavigationProps,
|
||||
NotesScreenParams
|
||||
} from "../../services/navigation";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SearchService from "../../services/search";
|
||||
import useNavigationStore, {
|
||||
HeaderRightButton,
|
||||
NotesScreenParams,
|
||||
RouteName
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
@@ -117,10 +115,21 @@ const NotesPage = ({
|
||||
focusOnInit: !focusControl
|
||||
});
|
||||
|
||||
const syncWithNavigation = () => {
|
||||
const prepareSearch = React.useCallback(() => {
|
||||
const { item } = params.current;
|
||||
SearchService.update({
|
||||
placeholder: `Search in ${alias}`,
|
||||
type: "notes",
|
||||
title: item.type === "tag" ? "#" + alias : toCamelCase(item.title),
|
||||
get: () => {
|
||||
return get(params.current, false);
|
||||
}
|
||||
});
|
||||
}, [alias, get]);
|
||||
|
||||
const syncWithNavigation = React.useCallback(() => {
|
||||
const { item, title } = params.current;
|
||||
const alias = getAlias(params.current);
|
||||
console.log(alias, title, "syncWithNavigation", params.current);
|
||||
useNavigationStore.getState().update(
|
||||
{
|
||||
name: route.name,
|
||||
@@ -146,35 +155,44 @@ const NotesPage = ({
|
||||
color: item.title,
|
||||
notebook: (item as TopicType).notebookId
|
||||
});
|
||||
};
|
||||
}, [
|
||||
isMonograph,
|
||||
onPressFloatingButton,
|
||||
prepareSearch,
|
||||
rightButtons,
|
||||
route.name
|
||||
]);
|
||||
|
||||
const onRequestUpdate = (data?: NotesScreenParams) => {
|
||||
const isNew = data && data?.item?.id !== params.current?.item?.id;
|
||||
if (data) params.current = data;
|
||||
params.current.title = params.current.title || params.current.item.title;
|
||||
const { item } = params.current;
|
||||
try {
|
||||
if (isNew) setLoadingNotes(true);
|
||||
const notes = get(params.current, true) as NoteType[];
|
||||
if (
|
||||
(item.type === "tag" || item.type === "color") &&
|
||||
(!notes || notes.length === 0)
|
||||
) {
|
||||
return Navigation.goBack();
|
||||
const onRequestUpdate = React.useCallback(
|
||||
(data?: NotesScreenParams) => {
|
||||
const isNew = data && data?.item?.id !== params.current?.item?.id;
|
||||
if (data) params.current = data;
|
||||
params.current.title = params.current.title || params.current.item.title;
|
||||
const { item } = params.current;
|
||||
try {
|
||||
if (isNew) setLoadingNotes(true);
|
||||
const notes = get(params.current, true) as NoteType[];
|
||||
if (
|
||||
(item.type === "tag" || item.type === "color") &&
|
||||
(!notes || notes.length === 0)
|
||||
) {
|
||||
return Navigation.goBack();
|
||||
}
|
||||
if (item.type === "topic") setWarning(!isSynced(params.current));
|
||||
setNotes(notes);
|
||||
syncWithNavigation();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
if (item.type === "topic") setWarning(!isSynced(params.current));
|
||||
setNotes(notes);
|
||||
syncWithNavigation();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
},
|
||||
[get, syncWithNavigation]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (loadingNotes) {
|
||||
setTimeout(() => setLoadingNotes(false), 300);
|
||||
}
|
||||
}, [notes]);
|
||||
}, [loadingNotes, notes]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(route.name, onRequestUpdate);
|
||||
@@ -182,19 +200,7 @@ const NotesPage = ({
|
||||
setOnFirstSave(null);
|
||||
eUnSubscribeEvent(route.name, onRequestUpdate);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const prepareSearch = () => {
|
||||
const { item } = params.current;
|
||||
SearchService.update({
|
||||
placeholder: `Search in ${alias}`,
|
||||
type: "notes",
|
||||
title: item.type === "tag" ? "#" + alias : toCamelCase(item.title),
|
||||
get: () => {
|
||||
return get(params.current, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
}, [onRequestUpdate, route.name]);
|
||||
|
||||
return (
|
||||
<DelayLayout
|
||||
|
||||
@@ -20,10 +20,8 @@ import { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import React from "react";
|
||||
import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
import Navigation, {
|
||||
NavigationProps,
|
||||
NotesScreenParams
|
||||
} from "../../services/navigation";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import { NotesScreenParams } from "../../stores/use-navigation-store";
|
||||
import { MonographType } from "../../utils/types";
|
||||
import { openMonographsWebpage } from "./common";
|
||||
export const Monographs = ({
|
||||
|
||||
@@ -20,10 +20,8 @@ import { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import React from "react";
|
||||
import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
import Navigation, {
|
||||
NavigationProps,
|
||||
NotesScreenParams
|
||||
} from "../../services/navigation";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import { NotesScreenParams } from "../../stores/use-navigation-store";
|
||||
import { NoteType, TagType } from "../../utils/types";
|
||||
import { getAlias, openEditor } from "./common";
|
||||
export const TaggedNotes = ({
|
||||
|
||||
@@ -22,10 +22,8 @@ import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
import { MoveNotes } from "../../components/sheets/move-notes/movenote";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import Navigation, {
|
||||
NavigationProps,
|
||||
NotesScreenParams
|
||||
} from "../../services/navigation";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import { NotesScreenParams } from "../../stores/use-navigation-store";
|
||||
import { eOpenAddTopicDialog } from "../../utils/events";
|
||||
import { NotebookType, TopicType } from "../../utils/types";
|
||||
import { openEditor } from "./common";
|
||||
|
||||
@@ -48,7 +48,7 @@ export const Search = ({ navigation, route }) => {
|
||||
setSearchResults([]);
|
||||
setSearchStatus(false, null);
|
||||
};
|
||||
}, []);
|
||||
}, [setSearchResults, setSearchStatus]);
|
||||
|
||||
return (
|
||||
<DelayLayout wait={searching}>
|
||||
|
||||
@@ -180,7 +180,7 @@ export const MFASetup = ({
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
}, [method?.id]);
|
||||
|
||||
const codeHelpText = {
|
||||
app: "After putting the above code in authenticator app, the app will display a code that you can enter below.",
|
||||
|
||||
@@ -78,59 +78,62 @@ export default function DebugLogs() {
|
||||
setLogs(logs);
|
||||
}
|
||||
})();
|
||||
}, [seconds]);
|
||||
}, [currentLog, seconds, start]);
|
||||
|
||||
const renderItem = ({ item }: { item: LogMessage; index: number }) => {
|
||||
const background =
|
||||
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||
? hexToRGBA(colors.red, 0.2)
|
||||
: item.level === LogLevel.Warn
|
||||
? hexToRGBA(colors.orange, 0.2)
|
||||
: "transparent";
|
||||
const renderItem = React.useCallback(
|
||||
({ item }: { item: LogMessage; index: number }) => {
|
||||
const background =
|
||||
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||
? hexToRGBA(colors.red, 0.2)
|
||||
: item.level === LogLevel.Warn
|
||||
? hexToRGBA(colors.orange, 0.2)
|
||||
: "transparent";
|
||||
|
||||
const color =
|
||||
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||
? colors.red
|
||||
: item.level === LogLevel.Warn
|
||||
? colors.orange
|
||||
: colors.pri;
|
||||
const color =
|
||||
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||
? colors.red
|
||||
: item.level === LogLevel.Warn
|
||||
? colors.orange
|
||||
: colors.pri;
|
||||
|
||||
return !item ? null : (
|
||||
<TouchableOpacity
|
||||
activeOpacity={1}
|
||||
onLongPress={() => {
|
||||
Clipboard.setString(format(item));
|
||||
ToastEvent.show({
|
||||
heading: "Debug log copied!",
|
||||
context: "global",
|
||||
type: "success"
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
backgroundColor: background,
|
||||
flexShrink: 1,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.nav
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
style={{
|
||||
flexShrink: 1,
|
||||
flexWrap: "wrap",
|
||||
fontFamily: Platform.OS === "ios" ? "Menlo" : "monospace"
|
||||
return !item ? null : (
|
||||
<TouchableOpacity
|
||||
activeOpacity={1}
|
||||
onLongPress={() => {
|
||||
Clipboard.setString(format(item));
|
||||
ToastEvent.show({
|
||||
heading: "Debug log copied!",
|
||||
context: "global",
|
||||
type: "success"
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
backgroundColor: background,
|
||||
flexShrink: 1,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.nav
|
||||
}}
|
||||
size={12}
|
||||
color={color}
|
||||
>
|
||||
{format(item)}
|
||||
</Paragraph>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
<Paragraph
|
||||
style={{
|
||||
flexShrink: 1,
|
||||
flexWrap: "wrap",
|
||||
fontFamily: Platform.OS === "ios" ? "Menlo" : "monospace"
|
||||
}}
|
||||
size={12}
|
||||
color={color}
|
||||
>
|
||||
{format(item)}
|
||||
</Paragraph>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
},
|
||||
[colors.nav, colors.orange, colors.pri, colors.red]
|
||||
);
|
||||
|
||||
const downloadLogs = async () => {
|
||||
const downloadLogs = React.useCallback(async () => {
|
||||
try {
|
||||
let path = null;
|
||||
const fileName = sanitizeFilename(`notesnook_logs_${Date.now()}`);
|
||||
@@ -165,9 +168,9 @@ export default function DebugLogs() {
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
}, [currentLog?.logs]);
|
||||
|
||||
const copyLogs = () => {
|
||||
const copyLogs = React.useCallback(() => {
|
||||
const data = currentLog?.logs
|
||||
.map((log) => {
|
||||
return !log ? "" : format(log);
|
||||
@@ -180,9 +183,9 @@ export default function DebugLogs() {
|
||||
context: "global",
|
||||
type: "success"
|
||||
});
|
||||
};
|
||||
}, [currentLog?.logs]);
|
||||
|
||||
const clearLogs = () => {
|
||||
const clearLogs = React.useCallback(() => {
|
||||
if (!currentLog) return;
|
||||
presentDialog({
|
||||
title: "Clear logs",
|
||||
@@ -203,7 +206,7 @@ export default function DebugLogs() {
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}, [currentLog, logs]);
|
||||
|
||||
return (
|
||||
<View
|
||||
|
||||
@@ -45,58 +45,61 @@ export default function ToolSheet({
|
||||
const data = useDragState((state) => state.data);
|
||||
const ungrouped = getUngroupedTools(data) as ToolId[];
|
||||
|
||||
const renderTool = React.useCallback((item: ToolId) => {
|
||||
const tool = findToolById(item);
|
||||
const iconSvgString = tool ? getToolIcon(tool.icon as ToolId) : null;
|
||||
return (
|
||||
<PressableButton
|
||||
key={item}
|
||||
type="grayBg"
|
||||
onPress={() => {
|
||||
const _data = useDragState.getState().data.slice();
|
||||
if (group.groupIndex !== undefined) {
|
||||
(_data[group.groupIndex][group.index] as ToolId[]).unshift(
|
||||
item as ToolId
|
||||
);
|
||||
} else {
|
||||
_data[group.index].unshift(item);
|
||||
}
|
||||
useDragState.getState().setData(_data);
|
||||
}}
|
||||
customStyle={{
|
||||
marginBottom: 10,
|
||||
width: "100%",
|
||||
height: 50,
|
||||
paddingHorizontal: 12,
|
||||
paddingRight: 0,
|
||||
borderRadius: 5,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
const renderTool = React.useCallback(
|
||||
(item: ToolId) => {
|
||||
const tool = findToolById(item);
|
||||
const iconSvgString = tool ? getToolIcon(tool.icon as ToolId) : null;
|
||||
return (
|
||||
<PressableButton
|
||||
key={item}
|
||||
type="grayBg"
|
||||
onPress={() => {
|
||||
const _data = useDragState.getState().data.slice();
|
||||
if (group.groupIndex !== undefined) {
|
||||
(_data[group.groupIndex][group.index] as ToolId[]).unshift(
|
||||
item as ToolId
|
||||
);
|
||||
} else {
|
||||
_data[group.index].unshift(item);
|
||||
}
|
||||
useDragState.getState().setData(_data);
|
||||
}}
|
||||
customStyle={{
|
||||
marginBottom: 10,
|
||||
width: "100%",
|
||||
height: 50,
|
||||
paddingHorizontal: 12,
|
||||
paddingRight: 0,
|
||||
borderRadius: 5,
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
>
|
||||
{iconSvgString ? (
|
||||
<SvgView width={23} height={23} src={iconSvgString} />
|
||||
) : null}
|
||||
<Paragraph
|
||||
<View
|
||||
style={{
|
||||
marginLeft: iconSvgString ? 10 : 0
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
color={colors.pri}
|
||||
size={SIZE.sm}
|
||||
>
|
||||
{tool?.title}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</PressableButton>
|
||||
);
|
||||
}, []);
|
||||
{iconSvgString ? (
|
||||
<SvgView width={23} height={23} src={iconSvgString} />
|
||||
) : null}
|
||||
<Paragraph
|
||||
style={{
|
||||
marginLeft: iconSvgString ? 10 : 0
|
||||
}}
|
||||
color={colors.pri}
|
||||
size={SIZE.sm}
|
||||
>
|
||||
{tool?.title}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</PressableButton>
|
||||
);
|
||||
},
|
||||
[colors.pri, group.groupIndex, group.index]
|
||||
);
|
||||
|
||||
return (
|
||||
<View
|
||||
|
||||
@@ -64,60 +64,64 @@ export const Tool = ({
|
||||
const iconSvgString =
|
||||
isSubgroup || !tool ? null : getToolIcon(tool.icon as ToolId);
|
||||
|
||||
const buttons = isSubgroup
|
||||
? [
|
||||
{
|
||||
name: "minus",
|
||||
onPress: () => {
|
||||
presentDialog({
|
||||
context: "global",
|
||||
title: "Delete collapsed section?",
|
||||
positiveText: "Delete",
|
||||
paragraph:
|
||||
"All tools in the collapsed section will also be removed.",
|
||||
positivePress: () => {
|
||||
const buttons = React.useMemo(
|
||||
() =>
|
||||
isSubgroup
|
||||
? [
|
||||
{
|
||||
name: "minus",
|
||||
onPress: () => {
|
||||
presentDialog({
|
||||
context: "global",
|
||||
title: "Delete collapsed section?",
|
||||
positiveText: "Delete",
|
||||
paragraph:
|
||||
"All tools in the collapsed section will also be removed.",
|
||||
positivePress: () => {
|
||||
if (typeof groupIndex !== "number") return;
|
||||
const _data = useDragState.getState().data.slice();
|
||||
_data[groupIndex].splice(index, 1);
|
||||
setData(_data);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "plus",
|
||||
onPress: () => {
|
||||
ToolSheet.present({
|
||||
item,
|
||||
index,
|
||||
groupIndex,
|
||||
parentIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
name: "minus",
|
||||
onPress: () => {
|
||||
if (typeof groupIndex !== "number") return;
|
||||
const _data = useDragState.getState().data.slice();
|
||||
_data[groupIndex].splice(index, 1);
|
||||
if (typeof parentIndex !== "number") {
|
||||
const index = _data[groupIndex].findIndex(
|
||||
(tool) => tool === item
|
||||
);
|
||||
_data[groupIndex].splice(index, 1);
|
||||
} else {
|
||||
const index = (
|
||||
_data[parentIndex][groupIndex] as ToolId[]
|
||||
).findIndex((tool: string) => tool === item);
|
||||
(_data[parentIndex][groupIndex] as ToolId[]).splice(index, 1);
|
||||
}
|
||||
console.log(_data[groupIndex]);
|
||||
setData(_data);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "plus",
|
||||
onPress: () => {
|
||||
ToolSheet.present({
|
||||
item,
|
||||
index,
|
||||
groupIndex,
|
||||
parentIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
name: "minus",
|
||||
onPress: () => {
|
||||
if (typeof groupIndex !== "number") return;
|
||||
const _data = useDragState.getState().data.slice();
|
||||
if (typeof parentIndex !== "number") {
|
||||
const index = _data[groupIndex].findIndex(
|
||||
(tool) => tool === item
|
||||
);
|
||||
_data[groupIndex].splice(index, 1);
|
||||
} else {
|
||||
const index = (
|
||||
_data[parentIndex][groupIndex] as ToolId[]
|
||||
).findIndex((tool: string) => tool === item);
|
||||
(_data[parentIndex][groupIndex] as ToolId[]).splice(index, 1);
|
||||
}
|
||||
console.log(_data[groupIndex]);
|
||||
setData(_data);
|
||||
}
|
||||
}
|
||||
];
|
||||
],
|
||||
[groupIndex, index, isSubgroup, item, parentIndex, setData]
|
||||
);
|
||||
|
||||
if (parentIndex === undefined && !isSubgroup) {
|
||||
buttons.unshift({
|
||||
@@ -236,7 +240,20 @@ export const Tool = ({
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
[]
|
||||
[
|
||||
buttons,
|
||||
colors.bg,
|
||||
colors.icon,
|
||||
colors.nav,
|
||||
colors.pri,
|
||||
groupIndex,
|
||||
iconSvgString,
|
||||
index,
|
||||
isDragged,
|
||||
isSubgroup,
|
||||
item,
|
||||
tool?.title
|
||||
]
|
||||
);
|
||||
|
||||
const onDrop = (data: DraxDragWithReceiverEventData) => {
|
||||
|
||||
@@ -24,13 +24,6 @@ import Group from "./group";
|
||||
import Home from "./home";
|
||||
import { RouteParams } from "./types";
|
||||
const SettingsStack = createNativeStackNavigator<RouteParams>();
|
||||
const screenListeners = {
|
||||
beforeRemove: (e: any) => {
|
||||
if (e.target?.startsWith("SettingsGroup")) {
|
||||
useNavigationStore.getState().update({ name: "Settings" }, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// const Home = React.lazy(() => import(/* webpackChunkName: "settings-home" */ './home'));
|
||||
// const Group = React.lazy(() => import(/* webpackChunkName: "settings-group" */ './group'));
|
||||
@@ -65,7 +58,13 @@ export const Settings = () => {
|
||||
return (
|
||||
<SettingsStack.Navigator
|
||||
initialRouteName="SettingsHome"
|
||||
screenListeners={screenListeners}
|
||||
screenListeners={{
|
||||
beforeRemove: (e) => {
|
||||
if (e.target?.startsWith("SettingsGroup")) {
|
||||
useNavigationStore.getState().update({ name: "Settings" }, false);
|
||||
}
|
||||
}
|
||||
}}
|
||||
screenOptions={{
|
||||
animation: "none",
|
||||
headerShown: false,
|
||||
|
||||
@@ -137,7 +137,7 @@ export const useTip = (
|
||||
return () => {
|
||||
clearInterval(intervalRef.current);
|
||||
};
|
||||
}, [context, fallback]);
|
||||
}, [context, fallback, options.delay, options?.rotate]);
|
||||
|
||||
return tip;
|
||||
};
|
||||
|
||||
@@ -58,6 +58,10 @@ export type Item =
|
||||
|
||||
export type MonographType = {
|
||||
type: "monograph";
|
||||
id: string;
|
||||
title: string;
|
||||
dateModified: number;
|
||||
dateCreated: number;
|
||||
};
|
||||
|
||||
export interface Entity<TType extends EntityTypes> {
|
||||
|
||||
Reference in New Issue
Block a user