diff --git a/apps/mobile/app/components/container/floating-button.tsx b/apps/mobile/app/components/container/floating-button.tsx
index 3dc8e7990..2f0402594 100644
--- a/apps/mobile/app/components/container/floating-button.tsx
+++ b/apps/mobile/app/components/container/floating-button.tsx
@@ -20,7 +20,7 @@ along with this program. If not, see .
import { useThemeColors } from "@notesnook/theme";
import { useRoute } from "@react-navigation/native";
import React, { useCallback, useEffect } from "react";
-import { Keyboard, TouchableOpacity, View } from "react-native";
+import { Keyboard, TouchableOpacity, View, ViewStyle } from "react-native";
import Animated, {
Easing,
useAnimatedStyle,
@@ -43,6 +43,9 @@ interface FloatingButtonProps {
alwaysVisible?: boolean;
icon?: string;
testID?: string;
+ position?: "left" | "right";
+ size?: "small" | "large";
+ style?: ViewStyle;
}
const FloatingButton = ({
@@ -50,7 +53,10 @@ const FloatingButton = ({
color,
alwaysVisible = false,
icon,
- testID
+ testID,
+ position = "right",
+ size = "large",
+ style
}: FloatingButtonProps) => {
const { colors } = useThemeColors();
const deviceMode = useSettingStore((state) => state.deviceMode);
@@ -112,9 +118,11 @@ const FloatingButton = ({
style={[
{
position: "absolute",
- right: DefaultAppStyles.GAP,
+ right: position === "right" ? DefaultAppStyles.GAP : undefined,
+ left: position === "left" ? DefaultAppStyles.GAP : undefined,
bottom: 20,
- zIndex: 10
+ zIndex: 10,
+ ...style
},
animatedStyle
]}
@@ -123,8 +131,8 @@ const FloatingButton = ({
testID={testID || notesnook.buttons.add}
activeOpacity={0.95}
style={{
- ...getElevationStyle(10),
- borderRadius: 20,
+ ...getElevationStyle(5),
+ borderRadius: size === "small" ? 15 : 20,
borderTopWidth: 0,
borderBottomWidth: 0,
borderLeftWidth: 0,
@@ -137,10 +145,10 @@ const FloatingButton = ({
style={{
alignItems: "center",
justifyContent: "center",
- height: normalize(60),
- width: normalize(60),
+ height: normalize(size === "small" ? 40 : 60),
+ width: normalize(size === "small" ? 40 : 60),
backgroundColor: colors.primary.shade,
- borderRadius: 20
+ borderRadius: size === "small" ? 15 : 20
}}
>
diff --git a/apps/mobile/app/components/sheet-provider/index.js b/apps/mobile/app/components/sheet-provider/index.js
index 4331ee156..49cacce50 100644
--- a/apps/mobile/app/components/sheet-provider/index.js
+++ b/apps/mobile/app/components/sheet-provider/index.js
@@ -95,6 +95,8 @@ const SheetProvider = ({ context = "global" }) => {
[context]
);
+ console.log(data?.keyboardHandlerDisabled);
+
return !visible || !data ? null : (
.
+*/
+
+import { Notebook, VirtualizedGrouping } from "@notesnook/core";
+import { strings } from "@notesnook/intl";
+import { useThemeColors } from "@notesnook/theme";
+import React, { useEffect, useState } from "react";
+import { FlatList, View } from "react-native";
+import { db } from "../../../common/database";
+import NotebookScreen from "../../../screens/notebook";
+import {
+ eSendEvent,
+ eSubscribeEvent,
+ presentSheet
+} from "../../../services/event-manager";
+import {
+ createNotebookTreeStores,
+ TreeItem
+} from "../../../stores/create-notebook-tree-stores";
+import useNavigationStore from "../../../stores/use-navigation-store";
+import { eCloseSheet, eOnNotebookUpdated } from "../../../utils/events";
+import { AppFontSize } from "../../../utils/size";
+import { DefaultAppStyles } from "../../../utils/styles";
+import { sleep } from "../../../utils/time";
+import { Properties } from "../../properties";
+import SheetProvider from "../../sheet-provider";
+import { NotebookItem } from "../../side-menu/notebook-item";
+import { useSideMenuNotebookTreeStore } from "../../side-menu/stores";
+import { IconButton } from "../../ui/icon-button";
+import Paragraph from "../../ui/typography/paragraph";
+import { AddNotebookSheet } from "../add-notebook";
+
+const {
+ useNotebookExpandedStore,
+ useNotebookSelectionStore,
+ useNotebookTreeStore
+} = createNotebookTreeStores(false, false, "notebook-tree-sheet");
+
+useNotebookSelectionStore.setState({
+ multiSelect: true
+});
+export const Notebooks = (props: {
+ rootNotebook: Notebook;
+ close?: (ctx?: string) => void;
+}) => {
+ const tree = useNotebookTreeStore((state) => state.tree);
+ const [isLoading, setIsLoading] = useState(true);
+ const { colors } = useThemeColors();
+ const [notebooks, setNotebooks] = useState();
+ const [filteredNotebooks, setFilteredNotebooks] =
+ React.useState>();
+ const searchTimer = React.useRef();
+ const lastQuery = React.useRef();
+ const loadRootNotebooks = React.useCallback(async () => {
+ const notebooks = await db.relations
+ .from(
+ {
+ type: "notebook",
+ id: props.rootNotebook.id
+ },
+ "notebook"
+ )
+ .selector.items(undefined, db.settings.getGroupOptions("notebooks"));
+ const items = await useNotebookTreeStore
+ .getState()
+ .addNotebooks("root", notebooks, 0);
+ setNotebooks(notebooks);
+ useNotebookTreeStore.getState().setTree(items);
+ }, [props.rootNotebook.id]);
+
+ const updateNotebooks = React.useCallback(() => {
+ loadRootNotebooks();
+ }, [loadRootNotebooks]);
+
+ useEffect(() => {
+ updateNotebooks();
+ }, [updateNotebooks]);
+
+ useEffect(() => {
+ (async () => {
+ loadRootNotebooks();
+ setIsLoading(false);
+ })();
+ }, [loadRootNotebooks]);
+
+ useEffect(() => {
+ const sub = eSubscribeEvent(eOnNotebookUpdated, (id) => {
+ if (id === props.rootNotebook.id) {
+ updateNotebooks();
+ }
+ });
+ return () => {
+ sub?.unsubscribe();
+ };
+ }, [updateNotebooks, props.rootNotebook.id]);
+
+ useEffect(() => {
+ useNotebookSelectionStore.setState({
+ selectAll: async () => {
+ const allNotebooks = await db.notebooks.all.items();
+ const allSelected = allNotebooks.every((notebook) => {
+ return (
+ useNotebookSelectionStore.getState().selection[notebook.id] ===
+ "selected"
+ );
+ });
+
+ if (allSelected) {
+ useNotebookSelectionStore.setState({
+ selection: {}
+ });
+ return;
+ }
+
+ useNotebookSelectionStore.setState({
+ selection: allNotebooks.reduce((acc: any, item) => {
+ acc[item.id] = "selected";
+ return acc;
+ }, {})
+ });
+ }
+ });
+ }, []);
+
+ const renderItem = React.useCallback(
+ (info: { item: TreeItem; index: number }) => {
+ return ;
+ },
+ []
+ );
+
+ return (
+
+
+
+
+
+ Sub notebooks
+
+
+ {
+ AddNotebookSheet.present(props.rootNotebook, undefined, "local");
+ }}
+ />
+
+ {!notebooks || notebooks.length === 0 ? (
+
+ {strings.emptyPlaceholders("notebook")}
+
+ ) : (
+ <>
+ item.notebook.id}
+ windowSize={3}
+ ListHeaderComponent={
+
+ }
+ renderItem={renderItem}
+ />
+ >
+ )}
+
+ );
+};
+
+Notebooks.present = (notebook: Notebook) => {
+ if (!notebook) return;
+ presentSheet({
+ component: (ref, close) => (
+
+ ),
+ keyboardHandlerDisabled: true
+ });
+};
+
+const NotebookItemWrapper = React.memo(
+ ({ item, index }: { item: TreeItem; index: number }) => {
+ const expanded = useNotebookExpandedStore(
+ (state) => state.expanded[item.notebook.id]
+ );
+
+ const selectionEnabled = useNotebookSelectionStore(
+ (state) => state.enabled
+ );
+ const selected = useNotebookSelectionStore(
+ (state) => state.selection[item.notebook.id] === "selected"
+ );
+ const focused = useNavigationStore(
+ (state) => state.focusedRouteId === item.notebook.id
+ );
+
+ const onItemUpdate = React.useCallback(async () => {
+ const notebook = await db.notebooks.notebook(item.notebook.id);
+ if (notebook) {
+ useSideMenuNotebookTreeStore
+ .getState()
+ .updateItem(item.notebook.id, notebook);
+ if (expanded) {
+ useSideMenuNotebookTreeStore
+ .getState()
+ .setTree(
+ await useSideMenuNotebookTreeStore
+ .getState()
+ .fetchAndAdd(item.notebook.id, item.depth + 1)
+ );
+ }
+ } else {
+ useSideMenuNotebookTreeStore.getState().removeItem(item.notebook.id);
+ }
+ }, [expanded, item.depth, item.notebook.id]);
+
+ return (
+
+ {
+ useNotebookExpandedStore.getState().setExpanded(item.notebook.id);
+ if (!expanded) {
+ useSideMenuNotebookTreeStore
+ .getState()
+ .setTree(
+ await useSideMenuNotebookTreeStore
+ .getState()
+ .fetchAndAdd(item.notebook.id, item.depth + 1)
+ );
+ } else {
+ useSideMenuNotebookTreeStore
+ .getState()
+ .removeChildren(item.notebook.id);
+ }
+ }}
+ selected={selected}
+ selectionEnabled={selectionEnabled}
+ selectionStore={useNotebookSelectionStore}
+ onItemUpdate={onItemUpdate}
+ focused={focused}
+ onPress={() => {
+ eSendEvent(eCloseSheet);
+ NotebookScreen.navigate(item.notebook, false);
+ }}
+ onLongPress={async () => {
+ eSendEvent(eCloseSheet);
+ await sleep(300);
+ Properties.present(item.notebook, false);
+ }}
+ />
+
+ );
+ },
+ (prev, next) => {
+ return (
+ prev.item.notebook.id === next.item.notebook.id &&
+ prev.item.notebook.dateModified === next.item.notebook.dateModified &&
+ prev.item.notebook.dateEdited === next.item.notebook.dateEdited &&
+ prev.item.hasChildren === next.item.hasChildren &&
+ prev.index === next.index &&
+ prev.item.parentId === next.item.parentId
+ );
+ }
+);
+NotebookItemWrapper.displayName = "NotebookItemWrapper";
diff --git a/apps/mobile/app/screens/notebook/index.tsx b/apps/mobile/app/screens/notebook/index.tsx
index 578d5db02..f3a276034 100644
--- a/apps/mobile/app/screens/notebook/index.tsx
+++ b/apps/mobile/app/screens/notebook/index.tsx
@@ -37,6 +37,9 @@ import useNavigationStore, {
import { eUpdateNotebookRoute } from "../../utils/events";
import { findRootNotebookId } from "../../utils/notebooks";
import { openEditor, setOnFirstSave } from "../notes/common";
+import { View } from "react-native";
+import { DefaultAppStyles } from "../../utils/styles";
+import { Notebooks } from "../../components/sheets/notebooks";
const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
const [notes, setNotes] = useState>();
@@ -193,10 +196,6 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
loading={loading}
CustomLisHeader={
{
- // AddNotebookSheet.present(params.current.item);
- // }}
breadcrumbs={breadcrumbs}
notebook={params.current.item}
totalNotes={notes?.placeholders.length || 0}
@@ -211,7 +210,36 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
}}
/>
-
+
+ {
+ Notebooks.present(params.current.item);
+ }}
+ style={{
+ position: "relative",
+ right: 0,
+ bottom: 5
+ }}
+ />
+
+
>
);
};
diff --git a/apps/mobile/native/fonts/MaterialCommunityIcons.ttf b/apps/mobile/native/fonts/MaterialCommunityIcons.ttf
index 4981bb9a1..d666b3c41 100644
Binary files a/apps/mobile/native/fonts/MaterialCommunityIcons.ttf and b/apps/mobile/native/fonts/MaterialCommunityIcons.ttf differ
diff --git a/apps/mobile/native/rspack.config.js b/apps/mobile/native/rspack.config.js
index 32d3e962b..735ede8b2 100644
--- a/apps/mobile/native/rspack.config.js
+++ b/apps/mobile/native/rspack.config.js
@@ -52,7 +52,7 @@ module.exports = (env) => {
parallelCodeSplitting: true,
cache: {
type: "persistent",
- buildDependencies: [__filename]
+ buildDependencies: [__filename, path.join(__dirname, "..", "package-lock.json"), path.join(__dirname, "..", "scripts","optimize-fonts.mjs")],
},
},
/**
diff --git a/apps/mobile/scripts/optimize-fonts.mjs b/apps/mobile/scripts/optimize-fonts.mjs
index 177396d59..8d02cf339 100644
--- a/apps/mobile/scripts/optimize-fonts.mjs
+++ b/apps/mobile/scripts/optimize-fonts.mjs
@@ -96,7 +96,10 @@ const EXTRA_ICON_NAMES = [
"dots-vertical",
"briefcase-outline",
"shield-outline",
- "brain"
+ "brain",
+ "file-tree-outline",
+ "format-list-bulleted",
+ "file-tree"
];
const __filename = fileURLToPath(import.meta.url);