diff --git a/apps/mobile/app/components/sheets/add-to/context.js b/apps/mobile/app/components/sheets/add-to/context.js
index 4307e2f76..02335cf7c 100644
--- a/apps/mobile/app/components/sheets/add-to/context.js
+++ b/apps/mobile/app/components/sheets/add-to/context.js
@@ -20,13 +20,9 @@ along with this program. If not, see .
import { createContext, useContext } from "react";
export const SelectionContext = createContext({
- enabled: false,
- selected: [],
toggleSelection: (item) => null,
deselect: (item) => null,
select: (item) => null,
- isSelected: (item) => null,
- setMultiSelect: () => null,
deselectAll: () => null
});
export const SelectionProvider = SelectionContext.Provider;
diff --git a/apps/mobile/app/components/sheets/add-to/index.js b/apps/mobile/app/components/sheets/add-to/index.js
index e8f08abb0..9aca6b8f9 100644
--- a/apps/mobile/app/components/sheets/add-to/index.js
+++ b/apps/mobile/app/components/sheets/add-to/index.js
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import React, { useCallback, useEffect, useMemo, useState } from "react";
+import React, { useCallback, useEffect, useMemo } from "react";
import { Keyboard, TouchableOpacity, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../../common/database";
@@ -35,10 +35,10 @@ import Paragraph from "../../ui/typography/paragraph";
import { SelectionProvider } from "./context";
import { FilteredList } from "./filtered-list";
import { ListItem } from "./list-item";
+import { useItemSelectionStore } from "./store";
const MoveNoteSheet = ({ note, actionSheetRef }) => {
const colors = useThemeStore((state) => state.colors);
- const [multiSelect, setMultiSelect] = useState(false);
const notebooks = useNotebookStore((state) =>
state.notebooks.filter((n) => n?.type === "notebook")
);
@@ -47,7 +47,9 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
(state) => state.selectedItemsList
);
const setNotebooks = useNotebookStore((state) => state.setNotebooks);
- const [itemState, setItemState] = useState({});
+
+ const multiSelect = useItemSelectionStore((state) => state.multiSelect);
+
const onAddNotebook = async (title) => {
if (!title || title.trim().length === 0) {
ToastEvent.show({
@@ -135,40 +137,39 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
const resetItemState = useCallback(
(state) => {
- setItemState(() => {
- const itemState = {};
- const notebooks = db.notebooks.all;
- for (let notebook of notebooks) {
- itemState[notebook.id] = state
+ const itemState = {};
+ const notebooks = db.notebooks.all;
+ for (let notebook of notebooks) {
+ itemState[notebook.id] = state
+ ? state
+ : areAllSelectedItemsInNotebook(notebook, selectedItemsList)
+ ? "selected"
+ : getSelectedNotesCountInItem(notebook, selectedItemsList) > 0
+ ? "intermediate"
+ : "deselected";
+ if (itemState[notebook.id] === "selected") {
+ contextValue.select(notebook);
+ } else {
+ contextValue.deselect(notebook);
+ }
+ for (let topic of notebook.topics) {
+ itemState[topic.id] = state
? state
- : areAllSelectedItemsInNotebook(notebook, selectedItemsList)
+ : areAllSelectedItemsInTopic(topic, selectedItemsList) &&
+ getSelectedNotesCountInItem(topic, selectedItemsList)
? "selected"
- : getSelectedNotesCountInItem(notebook, selectedItemsList) > 0
+ : getSelectedNotesCountInItem(topic, selectedItemsList) > 0
? "intermediate"
: "deselected";
- if (itemState[notebook.id] === "selected") {
- contextValue.select(notebook);
+ if (itemState[topic.id] === "selected") {
+ contextValue.select(topic);
} else {
- contextValue.deselect(notebook);
- }
- for (let topic of notebook.topics) {
- itemState[topic.id] = state
- ? state
- : areAllSelectedItemsInTopic(topic, selectedItemsList) &&
- getSelectedNotesCountInItem(topic, selectedItemsList)
- ? "selected"
- : getSelectedNotesCountInItem(topic, selectedItemsList) > 0
- ? "intermediate"
- : "deselected";
- if (itemState[topic.id] === "selected") {
- contextValue.select(topic);
- } else {
- contextValue.deselect(topic);
- }
+ contextValue.deselect(topic);
}
}
- return itemState;
- });
+ }
+
+ useItemSelectionStore.getState().setItemState(itemState);
},
[contextValue, getSelectedNotesCountInItem, selectedItemsList]
);
@@ -195,32 +196,26 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
}
const updateItemState = useCallback(function (item, state) {
- setItemState((itemState) => {
- const mergeState = {
- [item.id]: state
- };
- return {
- ...itemState,
- ...mergeState
- };
+ const itemState = useItemSelectionStore.getState().itemState;
+ const mergeState = {
+ [item.id]: state
+ };
+ useItemSelectionStore.getState().setItemState({
+ ...itemState,
+ ...mergeState
});
}, []);
const contextValue = useMemo(
() => ({
- enabled: multiSelect,
toggleSelection: (item) => {
- setItemState((itemState) => {
- if (itemState[item.id] === "selected") {
- updateItemState(item, "deselected");
- } else {
- updateItemState(item, "selected");
- }
-
- return itemState;
- });
+ const itemState = useItemSelectionStore.getState().itemState;
+ if (itemState[item.id] === "selected") {
+ updateItemState(item, "deselected");
+ } else {
+ updateItemState(item, "selected");
+ }
},
- setMultiSelect: setMultiSelect,
deselect: (item) => {
updateItemState(item, "deselected");
},
@@ -231,7 +226,7 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
resetItemState(state);
}
}),
- [multiSelect, resetItemState, updateItemState]
+ [resetItemState, updateItemState]
);
const getItemFromId = (id) => {
@@ -245,6 +240,7 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
const onSave = async () => {
const noteIds = note ? [note.id] : selectedItemsList.map((n) => n.id);
+ const itemState = useItemSelectionStore.getState().itemState;
for (const id in itemState) {
const item = getItemFromId(id);
if (itemState[id] === "selected") {
@@ -354,7 +350,7 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
}}
onPress={() => {
resetItemState();
- setMultiSelect(false);
+ useItemSelectionStore.getState().setMultiSelect(false);
}}
/>
@@ -389,13 +385,8 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
item={item}
key={item.id}
index={index}
- intermediate={itemState[item.id] === "intermediate"}
- removed={
- itemState[item.id] === "deselected" &&
- getSelectedNotesCountInItem(item) > 0
- }
+ hasNotes={getSelectedNotesCountInItem(item) > 0}
sheetRef={actionSheetRef}
- isSelected={itemState[item.id] === "selected"}
infoText={
<>
{item.topics.length === 1
@@ -405,17 +396,14 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
}
getListItems={getItemsForItem}
getSublistItemProps={(topic) => ({
- selected: itemState[topic.id] === "selected",
- intermediate: itemState[topic.id] === "intermediate",
- isSelected: itemState[topic.id] === "selected",
- removed:
- itemState[topic.id] === "deselected" &&
- getSelectedNotesCountInItem(topic) > 0,
+ hasNotes: getSelectedNotesCountInItem(topic) > 0,
style: {
marginBottom: 0,
height: 40
},
onPress: (item) => {
+ const itemState =
+ useItemSelectionStore.getState().itemState;
const currentState = itemState[item.id];
if (currentState !== "selected") {
resetItemState("deselected");
@@ -444,19 +432,22 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
onAddSublistItem={(item) => {
openAddTopicDialog(item);
}}
+ onPress={(item) => {
+ const itemState = useItemSelectionStore.getState().itemState;
+ const currentState = itemState[item.id];
+ if (currentState !== "selected") {
+ resetItemState("deselected");
+ contextValue.select(item);
+ } else {
+ contextValue.deselect(item);
+ }
+ }}
/>
)}
itemType="notebook"
onAddItem={async (title) => {
return await onAddNotebook(title);
}}
- // ListFooterComponent={
- //
- // }
/>
diff --git a/apps/mobile/app/components/sheets/add-to/list-item.js b/apps/mobile/app/components/sheets/add-to/list-item.js
index 7bff8fe29..acebbac79 100644
--- a/apps/mobile/app/components/sheets/add-to/list-item.js
+++ b/apps/mobile/app/components/sheets/add-to/list-item.js
@@ -27,13 +27,63 @@ import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { useSelectionContext } from "./context";
import { FilteredList } from "./filtered-list";
+import { useItemSelectionStore } from "./store";
-const _ListItem = ({
+const SelectionIndicator = ({ item, hasNotes, selectItem, onPress }) => {
+ const itemState = useItemSelectionStore((state) => state.itemState[item.id]);
+ const multiSelect = useItemSelectionStore((state) => state.multiSelect);
+
+ const isSelected = itemState === "selected";
+ const isIntermediate = itemState === "intermediate";
+ const isRemoved = !isSelected && hasNotes;
+ const colors = useThemeStore((state) => state.colors);
+
+ return (
+ {
+ if (multiSelect) return selectItem();
+ onPress?.(item);
+ }}
+ testID={
+ isRemoved
+ ? "close-circle-outline"
+ : isSelected
+ ? "check-circle-outline"
+ : isIntermediate
+ ? "minus-circle-outline"
+ : "checkbox-blank-circle-outline"
+ }
+ name={
+ isRemoved
+ ? "close-circle-outline"
+ : isSelected
+ ? "check-circle-outline"
+ : isIntermediate
+ ? "minus-circle-outline"
+ : "checkbox-blank-circle-outline"
+ }
+ />
+ );
+};
+
+export const ListItem = ({
item,
index,
icon,
infoText,
- intermediate,
hasSubList,
onPress,
onScrollEnd,
@@ -43,19 +93,21 @@ const _ListItem = ({
sublistItemType,
onAddItem,
getSublistItemProps,
- removed,
- isSelected,
hasHeaderSearch,
onAddSublistItem,
+ hasNotes,
sheetRef
}) => {
- const { enabled, toggleSelection, setMultiSelect } = useSelectionContext();
+ const { toggleSelection } = useSelectionContext();
+ const multiSelect = useItemSelectionStore((state) => state.multiSelect);
+
const colors = useThemeStore((state) => state.colors);
const [expanded, setExpanded] = useState(false);
function selectItem() {
toggleSelection(item);
}
+
return (
{
if (hasSubList) return setExpanded(!expanded);
- if (enabled) return selectItem();
+ if (multiSelect) return selectItem();
onPress?.(item);
}}
type={type}
onLongPress={() => {
- setMultiSelect(true);
+ useItemSelectionStore.getState().setMultiSelect(true);
selectItem();
}}
customStyle={{
@@ -97,43 +149,11 @@ const _ListItem = ({
alignItems: "center"
}}
>
- {
- selectItem();
- if (enabled) return;
- onPress?.(item);
- }}
- testID={
- removed
- ? "close-circle-outline"
- : isSelected
- ? "check-circle-outline"
- : intermediate
- ? "minus-circle-outline"
- : "checkbox-blank-circle-outline"
- }
- name={
- removed
- ? "close-circle-outline"
- : isSelected
- ? "check-circle-outline"
- : intermediate
- ? "minus-circle-outline"
- : "checkbox-blank-circle-outline"
- }
+
{hasSubList && expanded ? (
@@ -210,11 +230,3 @@ const _ListItem = ({
);
};
-
-export const ListItem = React.memo(_ListItem, (prev, next) => {
- if (prev.selected === undefined) return false;
- if (prev.isSelected !== next.isSelected) return false;
- if (prev.selected !== next.selected) return false;
- if (prev.intermediate !== next.intermediate) return false;
- return true;
-});
diff --git a/apps/mobile/app/components/sheets/add-to/store.ts b/apps/mobile/app/components/sheets/add-to/store.ts
new file mode 100644
index 000000000..827f47086
--- /dev/null
+++ b/apps/mobile/app/components/sheets/add-to/store.ts
@@ -0,0 +1,42 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+import create, { State } from "zustand";
+
+type SelectionItemState = Record<
+ string,
+ "intermediate" | "selected" | "deselected"
+>;
+
+export interface SelectionStore extends State {
+ itemState: SelectionItemState;
+ setItemState: (state: SelectionItemState) => void;
+ multiSelect: boolean;
+ setMultiSelect: (multiSelect: boolean) => void;
+}
+
+export const useItemSelectionStore = create((set) => ({
+ itemState: {},
+ setItemState: (itemState) => {
+ set({
+ itemState
+ });
+ },
+ multiSelect: false,
+ setMultiSelect: (multiSelect) => set({ multiSelect })
+}));