mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 11:47:54 +01:00
mobile: bug fixes
This commit is contained in:
committed by
Abdullah Atta
parent
3502469c1d
commit
787c36c754
@@ -44,7 +44,7 @@ export default function DelayLayout({
|
||||
}: IDelayLayoutProps) {
|
||||
const { colors } = useThemeColors();
|
||||
const loading = useDelayLayout(
|
||||
!props.delay || props.delay < 300 ? 300 : props.delay
|
||||
!props.delay || props.delay < 300 ? 0 : props.delay
|
||||
);
|
||||
const Placeholder = placeholder[props.type || "default"];
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import React, {
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import { FlatList, ScrollView, View } from "react-native";
|
||||
import { ActivityIndicator, FlatList, ScrollView, View } from "react-native";
|
||||
import { DDS } from "../../../services/device-detection";
|
||||
import {
|
||||
eSubscribeEvent,
|
||||
@@ -52,6 +52,8 @@ const JumpToSectionDialog = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const currentScrollPosition = useRef(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [groups, setGroups] = useState<
|
||||
{
|
||||
index: number;
|
||||
@@ -76,6 +78,7 @@ const JumpToSectionDialog = () => {
|
||||
data: VirtualizedGrouping<Item>;
|
||||
ref: RefObject<FlatList>;
|
||||
}) => {
|
||||
setLoading(true);
|
||||
setData(data);
|
||||
scrollRef.current = ref;
|
||||
setVisible(true);
|
||||
@@ -127,6 +130,7 @@ const JumpToSectionDialog = () => {
|
||||
});
|
||||
|
||||
setCurrentIndex(index < 0 ? 0 : index);
|
||||
setLoading(false);
|
||||
});
|
||||
}, [notes]);
|
||||
|
||||
@@ -152,54 +156,64 @@ const JumpToSectionDialog = () => {
|
||||
paddingTop: 30
|
||||
}}
|
||||
>
|
||||
<ScrollView
|
||||
style={{
|
||||
maxHeight: "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
size={SIZE.lg}
|
||||
color={colors.primary.accent}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
paddingBottom: 20
|
||||
marginBottom: 20
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ScrollView
|
||||
style={{
|
||||
maxHeight: "100%"
|
||||
}}
|
||||
>
|
||||
{groups?.map((item, index) => {
|
||||
return (
|
||||
<PressableButton
|
||||
key={item.group.id}
|
||||
onPress={() => onPress(item)}
|
||||
type={currentIndex === index ? "selected" : "transparent"}
|
||||
customStyle={{
|
||||
minWidth: "20%",
|
||||
width: null,
|
||||
paddingHorizontal: 12,
|
||||
margin: 5,
|
||||
borderRadius: 100,
|
||||
height: 25,
|
||||
marginVertical: 10
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
size={SIZE.sm}
|
||||
color={
|
||||
currentIndex === index
|
||||
? colors.selected.accent
|
||||
: colors.primary.accent
|
||||
}
|
||||
style={{
|
||||
textAlign: "center"
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
paddingBottom: 20
|
||||
}}
|
||||
>
|
||||
{groups?.map((item, index) => {
|
||||
return (
|
||||
<PressableButton
|
||||
key={item.group.id}
|
||||
onPress={() => onPress(item)}
|
||||
type={currentIndex === index ? "accent" : "transparent"}
|
||||
customStyle={{
|
||||
minWidth: "20%",
|
||||
width: null,
|
||||
paddingHorizontal: 12,
|
||||
margin: 5,
|
||||
borderRadius: 100,
|
||||
height: 30,
|
||||
marginVertical: 10
|
||||
}}
|
||||
>
|
||||
{item.group.title}
|
||||
</Paragraph>
|
||||
</PressableButton>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</ScrollView>
|
||||
<Paragraph
|
||||
size={SIZE.sm}
|
||||
color={
|
||||
currentIndex === index
|
||||
? colors.static.white
|
||||
: colors.primary.paragraph
|
||||
}
|
||||
style={{
|
||||
textAlign: "center"
|
||||
}}
|
||||
>
|
||||
{item.group.title}
|
||||
</Paragraph>
|
||||
</PressableButton>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</ScrollView>
|
||||
)}
|
||||
</View>
|
||||
</BaseDialog>
|
||||
);
|
||||
|
||||
@@ -49,6 +49,8 @@ export const Title = ({
|
||||
const isTag = title.startsWith("#");
|
||||
const onScroll = useCallback(
|
||||
(data: { x: number; y: number; id?: string; route: string }) => {
|
||||
if (data.route !== "Notebook") return;
|
||||
|
||||
if (data.route !== renderedInRoute || data.id !== id) return;
|
||||
if (data.y > 150) {
|
||||
if (!visible) return;
|
||||
|
||||
@@ -155,10 +155,10 @@ const NoteItem = ({
|
||||
<Paragraph
|
||||
numberOfLines={1}
|
||||
color={color?.colorCode || primaryColors.heading}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
paddingRight: 10
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
@@ -166,10 +166,10 @@ const NoteItem = ({
|
||||
<Heading
|
||||
numberOfLines={1}
|
||||
color={color?.colorCode || primaryColors.heading}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
size={SIZE.md}
|
||||
style={{
|
||||
paddingRight: 10
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</Heading>
|
||||
|
||||
@@ -156,6 +156,7 @@ export const NoteWrapper = React.memo<
|
||||
if (prev.item?.dateModified !== next.item?.dateModified) {
|
||||
return false;
|
||||
}
|
||||
if (prev.item?.id !== next.item?.id) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ export const NotebookWrapper = React.memo(
|
||||
if (prev.totalNotes !== next.totalNotes) return false;
|
||||
if (prev.date !== next.date) return false;
|
||||
if (prev.item?.dateModified !== next.item?.dateModified) return false;
|
||||
if (prev.item?.id !== next.item?.id) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ type ListProps = {
|
||||
isRenderedInActionSheet?: boolean;
|
||||
CustomListComponent?: React.JSX.ElementType;
|
||||
placeholder?: PlaceholderData;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
export default function List(props: ListProps) {
|
||||
@@ -116,16 +117,18 @@ export default function List(props: ListProps) {
|
||||
if (!event) return;
|
||||
eSendEvent(eScrollEvent, {
|
||||
y: event.nativeEvent.contentOffset.y,
|
||||
screen: props.renderedInRoute
|
||||
route: props.renderedInRoute,
|
||||
id: props.id || props.renderedInRoute
|
||||
});
|
||||
},
|
||||
[props.renderedInRoute]
|
||||
[props.renderedInRoute, props.id]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSendEvent(eScrollEvent, {
|
||||
y: 0,
|
||||
screen: props.renderedInRoute
|
||||
route: props.renderedInRoute,
|
||||
id: props.id || props.renderedInRoute
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
@@ -159,7 +162,10 @@ export default function List(props: ListProps) {
|
||||
onMomentumScrollEnd={() => {
|
||||
tabBarRef.current?.unlock();
|
||||
}}
|
||||
estimatedItemSize={isCompactModeEnabled ? 60 : 100}
|
||||
getItemType={(item: number, index: number) => {
|
||||
return props.data?.type(index);
|
||||
}}
|
||||
estimatedItemSize={isCompactModeEnabled ? 60 : 120}
|
||||
directionalLockEnabled={true}
|
||||
keyboardShouldPersistTaps="always"
|
||||
keyboardDismissMode="interactive"
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
VirtualizedGrouping
|
||||
} from "@notesnook/core";
|
||||
import { getSortValue } from "@notesnook/core/dist/utils/grouping";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
@@ -70,34 +70,79 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
const attachmentsCount = useRef(0);
|
||||
const [groupHeader, setGroupHeader] = useState<GroupHeader>();
|
||||
const previousIndex = useRef<number>();
|
||||
const refreshTimeout = useRef<NodeJS.Timeout>();
|
||||
const currentItemId = useRef<string>();
|
||||
|
||||
const refreshItem = useCallback((resolvedItem: any) => {
|
||||
if (!resolvedItem || !resolvedItem.data) {
|
||||
tags.current = undefined;
|
||||
notebooks.current = undefined;
|
||||
reminder.current = undefined;
|
||||
color.current = undefined;
|
||||
attachmentsCount.current = 0;
|
||||
totalNotes.current = 0;
|
||||
}
|
||||
|
||||
if (resolvedItem && resolvedItem.item) {
|
||||
const data = resolvedItem.data;
|
||||
if (resolvedItem.item.type === "note" && isNoteResolvedData(data)) {
|
||||
tags.current = data.tags;
|
||||
notebooks.current = data.notebooks;
|
||||
reminder.current = data.reminder;
|
||||
color.current = data.color;
|
||||
attachmentsCount.current = data.attachmentsCount || 0;
|
||||
} else if (
|
||||
resolvedItem.item.type === "notebook" &&
|
||||
typeof data === "number"
|
||||
) {
|
||||
totalNotes.current = data;
|
||||
} else if (resolvedItem.item.type === "tag" && typeof data === "number") {
|
||||
totalNotes.current = data;
|
||||
}
|
||||
currentItemId.current = resolvedItem.item.id;
|
||||
setItem(resolvedItem.item);
|
||||
setGroupHeader(resolvedItem.group);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (previousIndex.current !== index) {
|
||||
previousIndex.current = index;
|
||||
const resolvedItem = items?.cacheItem(index);
|
||||
refreshItem(resolvedItem);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
(async function () {
|
||||
try {
|
||||
const { item, data, group } =
|
||||
(await items?.item(index, resolveItems)) || {};
|
||||
if (!item) return;
|
||||
if (item.type === "note" && isNoteResolvedData(data)) {
|
||||
tags.current = data.tags;
|
||||
notebooks.current = data.notebooks;
|
||||
reminder.current = data.reminder;
|
||||
color.current = data.color;
|
||||
attachmentsCount.current = data.attachmentsCount;
|
||||
} else if (item.type === "notebook" && typeof data === "number") {
|
||||
totalNotes.current = data;
|
||||
} else if (item.type === "tag" && typeof data === "number") {
|
||||
totalNotes.current = data;
|
||||
}
|
||||
previousIndex.current = index;
|
||||
setItem(item);
|
||||
setGroupHeader(group);
|
||||
clearTimeout(refreshTimeout.current);
|
||||
const idx = index;
|
||||
refreshTimeout.current = setTimeout(async () => {
|
||||
if (idx !== previousIndex.current) {
|
||||
return;
|
||||
}
|
||||
const resolvedItem = await items?.item(idx, resolveItems);
|
||||
if (idx !== previousIndex.current) {
|
||||
console.log("cancel", idx, previousIndex.current);
|
||||
return;
|
||||
}
|
||||
|
||||
refreshItem(resolvedItem);
|
||||
}, 100);
|
||||
} catch (e) {
|
||||
console.log("Error", e);
|
||||
}
|
||||
})();
|
||||
}, [index, items]);
|
||||
}, [index, items, refreshItem]);
|
||||
|
||||
if (!item) return <View style={{ height: 100, width: "100%" }} />;
|
||||
if (!item)
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
height: 120,
|
||||
width: "100%"
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const type = ((item as TrashItem).itemType || item.type) as ItemType;
|
||||
switch (type) {
|
||||
@@ -220,30 +265,6 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
}
|
||||
}
|
||||
|
||||
function withDateEdited<
|
||||
T extends { dateEdited: number } | { dateModified: number }
|
||||
>(items: T[]): WithDateEdited<T> {
|
||||
let latestDateEdited = 0;
|
||||
items.forEach((item) => {
|
||||
const date = "dateEdited" in item ? item.dateEdited : item.dateModified;
|
||||
if (latestDateEdited < date) latestDateEdited = date;
|
||||
});
|
||||
return { dateEdited: latestDateEdited, items };
|
||||
}
|
||||
|
||||
export async function resolveItems(ids: string[], items: Item[]) {
|
||||
const { type } = items[0];
|
||||
if (type === "note") return resolveNotes(ids);
|
||||
else if (type === "notebook") {
|
||||
return Promise.all(ids.map((id) => db.notebooks.totalNotes(id)));
|
||||
} else if (type === "tag") {
|
||||
return Promise.all(
|
||||
ids.map((id) => db.relations.from({ id, type: "tag" }, "note").count())
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function getDate(item: Item, groupType?: GroupingKey): number {
|
||||
return (
|
||||
getSortValue(
|
||||
@@ -259,12 +280,38 @@ function getDate(item: Item, groupType?: GroupingKey): number {
|
||||
);
|
||||
}
|
||||
|
||||
function withDateEdited<
|
||||
T extends { dateEdited: number } | { dateModified: number }
|
||||
>(items: T[]): WithDateEdited<T> {
|
||||
let latestDateEdited = 0;
|
||||
items.forEach((item) => {
|
||||
const date = "dateEdited" in item ? item.dateEdited : item.dateModified;
|
||||
if (latestDateEdited < date) latestDateEdited = date;
|
||||
});
|
||||
return { dateEdited: latestDateEdited, items };
|
||||
}
|
||||
|
||||
export async function resolveItems(ids: string[], items: Item[]) {
|
||||
if (!ids.length || !items.length) return [];
|
||||
|
||||
const { type } = items[0];
|
||||
if (type === "note") return resolveNotes(ids);
|
||||
else if (type === "notebook") {
|
||||
return Promise.all(ids.map((id) => db.notebooks.totalNotes(id)));
|
||||
} else if (type === "tag") {
|
||||
return Promise.all(
|
||||
ids.map((id) => db.relations.from({ id, type: "tag" }, "note").count())
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
type NoteResolvedData = {
|
||||
notebooks?: NotebooksWithDateEdited;
|
||||
reminder?: Reminder;
|
||||
color?: Color;
|
||||
tags?: TagsWithDateEdited;
|
||||
attachmentsCount: number;
|
||||
attachmentsCount?: number;
|
||||
};
|
||||
async function resolveNotes(ids: string[]) {
|
||||
console.time("relations");
|
||||
@@ -332,19 +379,27 @@ async function resolveNotes(ids: string[]) {
|
||||
console.timeEnd("resolve");
|
||||
|
||||
const data: NoteResolvedData[] = [];
|
||||
for (const noteId in grouped) {
|
||||
for (const noteId of ids) {
|
||||
const group = grouped[noteId];
|
||||
if (!group) {
|
||||
data.push({});
|
||||
continue;
|
||||
}
|
||||
|
||||
data.push({
|
||||
color: group.color ? resolved.colors[group.color] : undefined,
|
||||
reminder: group.reminder ? resolved.reminders[group.reminder] : undefined,
|
||||
tags: withDateEdited(group.tags.map((id) => resolved.tags[id])),
|
||||
tags: withDateEdited(
|
||||
group.tags.map((id) => resolved.tags[id]).filter(Boolean)
|
||||
),
|
||||
notebooks: withDateEdited(
|
||||
group.notebooks.map((id) => resolved.notebooks[id])
|
||||
group.notebooks.map((id) => resolved.notebooks[id]).filter(Boolean)
|
||||
),
|
||||
attachmentsCount:
|
||||
(await db.attachments?.ofNote(noteId, "all").ids())?.length || 0
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,11 +180,9 @@ export const NotebookSheet = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (canShow) {
|
||||
setTimeout(async () => {
|
||||
setImmediate(async () => {
|
||||
if (!focusedRouteId) return;
|
||||
const nextRoot = await findRootNotebookId(focusedRouteId);
|
||||
setRoot(nextRoot);
|
||||
|
||||
if (nextRoot !== currentItem.current) {
|
||||
console.log(
|
||||
"NotebookSheet.useEffect.canShow",
|
||||
@@ -206,8 +204,9 @@ export const NotebookSheet = () => {
|
||||
ref.current?.show(snapPoint);
|
||||
}
|
||||
console.log("NotebookSheet.useEffect.canShow", focusedRouteId);
|
||||
setRoot(nextRoot);
|
||||
onRequestUpdate();
|
||||
}, 0);
|
||||
});
|
||||
} else {
|
||||
setSelection([]);
|
||||
setEnabled(false);
|
||||
@@ -305,28 +304,48 @@ export const NotebookSheet = () => {
|
||||
}}
|
||||
>
|
||||
{enabled ? (
|
||||
<IconButton
|
||||
customStyle={{
|
||||
marginLeft: 10,
|
||||
width: 40 * fontScale,
|
||||
height: 40 * fontScale
|
||||
}}
|
||||
onPress={async () => {
|
||||
await deleteItems(
|
||||
selection.map((notebook) => notebook.id),
|
||||
"notebook"
|
||||
);
|
||||
useSelectionStore.getState().clearSelection();
|
||||
setEnabled(false);
|
||||
setSelection([]);
|
||||
return;
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
tooltipText="Move to trash"
|
||||
tooltipPosition={1}
|
||||
name="delete"
|
||||
size={22}
|
||||
/>
|
||||
<>
|
||||
<IconButton
|
||||
customStyle={{
|
||||
marginLeft: 10,
|
||||
width: 40 * fontScale,
|
||||
height: 40 * fontScale
|
||||
}}
|
||||
onPress={async () => {
|
||||
await deleteItems(
|
||||
selection.map((notebook) => notebook.id),
|
||||
"notebook"
|
||||
);
|
||||
useSelectionStore.getState().clearSelection();
|
||||
setEnabled(false);
|
||||
setSelection([]);
|
||||
return;
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
tooltipText="Move to trash"
|
||||
tooltipPosition={1}
|
||||
name="delete"
|
||||
size={22}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
customStyle={{
|
||||
marginLeft: 10,
|
||||
width: 40 * fontScale,
|
||||
height: 40 * fontScale
|
||||
}}
|
||||
onPress={() => {
|
||||
useSelectionStore.getState().clearSelection();
|
||||
setEnabled(false);
|
||||
setSelection([]);
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
tooltipText="Clear selection"
|
||||
tooltipPosition={1}
|
||||
name="close"
|
||||
size={22}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<IconButton
|
||||
@@ -479,8 +498,7 @@ const NotebookItem = ({
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
paddingLeft: 0,
|
||||
paddingRight: 12,
|
||||
paddingHorizontal: 12,
|
||||
borderRadius: 0
|
||||
}}
|
||||
>
|
||||
@@ -490,26 +508,6 @@ const NotebookItem = ({
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{selection.enabled ? (
|
||||
<IconButton
|
||||
size={SIZE.lg}
|
||||
color={isSelected ? colors.selected.icon : colors.primary.icon}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
right={0}
|
||||
customStyle={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
name={
|
||||
isSelected
|
||||
? "check-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{nestedNotebooks?.ids.length ? (
|
||||
<IconButton
|
||||
size={SIZE.lg}
|
||||
@@ -523,24 +521,41 @@ const NotebookItem = ({
|
||||
bottom={0}
|
||||
right={0}
|
||||
customStyle={{
|
||||
width: 40,
|
||||
height: 40
|
||||
width: 35,
|
||||
height: 35
|
||||
}}
|
||||
name={expanded ? "chevron-down" : "chevron-right"}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selection?.enabled ? null : (
|
||||
<View
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<View
|
||||
style={{
|
||||
width: 35,
|
||||
height: 35
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{selection.enabled ? (
|
||||
<IconButton
|
||||
size={SIZE.lg}
|
||||
color={isSelected ? colors.selected.icon : colors.primary.icon}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
right={0}
|
||||
customStyle={{
|
||||
width: 35,
|
||||
height: 35,
|
||||
marginRight: 5
|
||||
}}
|
||||
name={
|
||||
isSelected
|
||||
? "check-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Paragraph
|
||||
color={
|
||||
isFocused ? colors.selected.paragraph : colors.secondary.paragraph
|
||||
|
||||
@@ -148,7 +148,9 @@ const Sort = ({ type, screen }) => {
|
||||
) : (
|
||||
Object.keys(SORT).map((item) =>
|
||||
(item === "dueDate" && screen !== "Reminders") ||
|
||||
(item === "title" && groupOptions.groupBy !== "none") ||
|
||||
(item === "title" &&
|
||||
groupOptions.groupBy !== "none" &&
|
||||
screen !== "TopicSheet") ||
|
||||
((screen !== "Tags" || screen !== "Reminders") &&
|
||||
item === "dateModified") ||
|
||||
((screen === "Tags" || screen === "Reminders") &&
|
||||
@@ -176,7 +178,7 @@ const Sort = ({ type, screen }) => {
|
||||
...groupOptions,
|
||||
sortBy: type === "trash" ? "dateDeleted" : item
|
||||
};
|
||||
if (type === "topics") {
|
||||
if (screen === "TopicSheet") {
|
||||
_groupOptions.groupBy = "none";
|
||||
}
|
||||
await updateGroupOptions(_groupOptions);
|
||||
|
||||
@@ -17,8 +17,9 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Color } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import { ColoredNotes } from "../../screens/notes/colored";
|
||||
@@ -31,7 +32,6 @@ import { presentDialog } from "../dialog/functions";
|
||||
import { PressableButton } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { Color } from "@notesnook/core";
|
||||
|
||||
export const ColorSection = React.memo(
|
||||
function ColorSection() {
|
||||
@@ -56,36 +56,10 @@ const ColorItem = React.memo(
|
||||
function ColorItem({ item }: { item: Color }) {
|
||||
const { colors, isDark } = useThemeColors();
|
||||
const setColorNotes = useMenuStore((state) => state.setColorNotes);
|
||||
const [headerTextState, setHeaderTextState] = useState<{
|
||||
id: string | undefined;
|
||||
}>({
|
||||
id: undefined
|
||||
});
|
||||
const isFocused = headerTextState?.id === item.id;
|
||||
|
||||
const onHeaderStateChange = useCallback(
|
||||
(state: any) => {
|
||||
setTimeout(() => {
|
||||
let id = state.focusedRouteId;
|
||||
if (id === item.id) {
|
||||
setHeaderTextState({ id: state.currentScreen.id });
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState({ id: undefined });
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
},
|
||||
[headerTextState, item.id]
|
||||
const isFocused = useNavigationStore(
|
||||
(state) => state.focusedRouteId === item.id
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const remove = useNavigationStore.subscribe(onHeaderStateChange);
|
||||
return () => {
|
||||
remove();
|
||||
};
|
||||
}, [headerTextState, onHeaderStateChange]);
|
||||
|
||||
const onPress = (item: Color) => {
|
||||
ColoredNotes.navigate(item, false);
|
||||
|
||||
|
||||
@@ -33,10 +33,9 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
export const MenuItem = React.memo(
|
||||
function MenuItem({ item, index, testID, rightBtn }) {
|
||||
const { colors } = useThemeColors();
|
||||
const [headerTextState, setHeaderTextState] = useState(
|
||||
useNavigationStore.getState().focusedRouteId
|
||||
const isFocused = useNavigationStore(
|
||||
(state) => state.focusedRouteId === item.name
|
||||
);
|
||||
let isFocused = headerTextState?.id === item.name;
|
||||
const primaryColors = isFocused ? colors.selected : colors.primary;
|
||||
|
||||
const _onPress = () => {
|
||||
@@ -57,29 +56,6 @@ export const MenuItem = React.memo(
|
||||
}
|
||||
};
|
||||
|
||||
const onHeaderStateChange = useCallback(
|
||||
(state) => {
|
||||
setTimeout(() => {
|
||||
let id = state.focusedRouteId;
|
||||
if (id === item.name) {
|
||||
setHeaderTextState({ id: state.focusedRouteId });
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState(null);
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
},
|
||||
[headerTextState, item.name]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let unsub = useNavigationStore.subscribe(onHeaderStateChange);
|
||||
return () => {
|
||||
unsub();
|
||||
};
|
||||
}, [headerTextState, onHeaderStateChange]);
|
||||
|
||||
return (
|
||||
<PressableButton
|
||||
testID={testID}
|
||||
|
||||
@@ -109,43 +109,12 @@ export const PinItem = React.memo(
|
||||
const setMenuPins = useMenuStore((state) => state.setMenuPins);
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [headerTextState, setHeaderTextState] = useState<{
|
||||
id?: string;
|
||||
}>({});
|
||||
const primaryColors =
|
||||
headerTextState?.id === item.id ? colors.selected : colors.primary;
|
||||
|
||||
const isFocused = headerTextState?.id === item.id;
|
||||
const color =
|
||||
headerTextState?.id === item.id
|
||||
? colors.selected.accent
|
||||
: colors.primary.icon;
|
||||
const fwdRef = useRef();
|
||||
|
||||
const onHeaderStateChange = useCallback(
|
||||
(state: any) => {
|
||||
setTimeout(() => {
|
||||
const id = state.focusedRouteId;
|
||||
if (id === item.id) {
|
||||
setHeaderTextState({
|
||||
id
|
||||
});
|
||||
} else {
|
||||
if (headerTextState !== null) {
|
||||
setHeaderTextState({});
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
},
|
||||
[headerTextState, item.id]
|
||||
const isFocused = useNavigationStore(
|
||||
(state) => state.focusedRouteId === item.id
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const remove = useNavigationStore.subscribe(onHeaderStateChange);
|
||||
return () => {
|
||||
remove();
|
||||
};
|
||||
}, [headerTextState, onHeaderStateChange]);
|
||||
const primaryColors = isFocused ? colors.selected : colors.primary;
|
||||
const color = isFocused ? colors.selected.accent : colors.primary.icon;
|
||||
const fwdRef = useRef();
|
||||
|
||||
const icons = {
|
||||
topic: "bookmark",
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Notebook, VirtualizedGrouping } from "@notesnook/core";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { db } from "../common/database";
|
||||
import { eSubscribeEvent, eUnSubscribeEvent } from "../services/event-manager";
|
||||
import { eGroupOptionsUpdated, eOnNotebookUpdated } from "../utils/events";
|
||||
@@ -29,9 +29,7 @@ export const useNotebook = (
|
||||
nestedNotebooks?: boolean
|
||||
) => {
|
||||
const [item, refresh] = useDBItem(id, "notebook", items);
|
||||
const [groupOptions, setGroupOptions] = useState(
|
||||
db.settings.getGroupOptions("notebooks")
|
||||
);
|
||||
const groupOptions = db.settings.getGroupOptions("notebooks");
|
||||
const [notebooks, setNotebooks] = useState<VirtualizedGrouping<Notebook>>();
|
||||
const { totalNotes: nestedNotebookNotesCount, getTotalNotes } =
|
||||
useTotalNotes("notebook");
|
||||
@@ -66,16 +64,6 @@ export const useNotebook = (
|
||||
}
|
||||
}, [item?.id, onRequestUpdate, nestedNotebooks]);
|
||||
|
||||
const onUpdate = useCallback(
|
||||
(type: string) => {
|
||||
if (type !== "notebooks") return;
|
||||
setGroupOptions({ ...(db.settings.getGroupOptions("notebooks") as any) });
|
||||
onRequestUpdate();
|
||||
console.log("useNotebook.onUpdate", id, Date.now());
|
||||
},
|
||||
[id, onRequestUpdate]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const onNotebookUpdate = (id?: string) => {
|
||||
if (typeof id === "string" && id !== id) return;
|
||||
@@ -87,13 +75,20 @@ export const useNotebook = (
|
||||
});
|
||||
};
|
||||
|
||||
const onUpdate = (type: string) => {
|
||||
console.log("event", type);
|
||||
if (type !== "notebooks") return;
|
||||
onRequestUpdate();
|
||||
console.log("useNotebook.onUpdate", item?.id, Date.now());
|
||||
};
|
||||
|
||||
eSubscribeEvent(eGroupOptionsUpdated, onUpdate);
|
||||
eSubscribeEvent(eOnNotebookUpdated, onNotebookUpdate);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eGroupOptionsUpdated, onUpdate);
|
||||
eUnSubscribeEvent(eOnNotebookUpdated, onNotebookUpdate);
|
||||
};
|
||||
}, [onUpdate, onRequestUpdate, id, refresh, nestedNotebooks]);
|
||||
}, [onRequestUpdate, item?.id, refresh, nestedNotebooks]);
|
||||
|
||||
return {
|
||||
notebook: item,
|
||||
|
||||
@@ -65,7 +65,7 @@ export const Home = ({ navigation, route }: NavigationProps<"Notes">) => {
|
||||
id={route.name}
|
||||
onPressDefaultRightButton={openEditor}
|
||||
/>
|
||||
<DelayLayout wait={loading} delay={500}>
|
||||
<DelayLayout wait={loading}>
|
||||
<List
|
||||
data={notes}
|
||||
dataType="note"
|
||||
|
||||
@@ -39,11 +39,23 @@ import { eUpdateNotebookRoute } from "../../utils/events";
|
||||
import { findRootNotebookId } from "../../utils/notebooks";
|
||||
import { openEditor, setOnFirstSave } from "../notes/common";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { resolveItems } from "../../components/list/list-item.wrapper";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import { View } from "react-native";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { IconButton } from "../../components/ui/icon-button";
|
||||
import { PressableButton } from "../../components/ui/pressable";
|
||||
|
||||
const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
const [notes, setNotes] = useState<VirtualizedGrouping<Note>>();
|
||||
const params = useRef<NotebookScreenParams>(route?.params);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [breadcrumbs, setBreadcrumbs] = useState<
|
||||
{
|
||||
id: string;
|
||||
title: string;
|
||||
}[]
|
||||
>([]);
|
||||
|
||||
useNavigationFocus(navigation, {
|
||||
onFocus: () => {
|
||||
@@ -89,13 +101,16 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
const notebook = await db.notebooks?.notebook(
|
||||
params?.current?.item?.id
|
||||
);
|
||||
|
||||
if (notebook) {
|
||||
const breadcrumbs = await db.notebooks.breadcrumbs(notebook.id);
|
||||
setBreadcrumbs(breadcrumbs);
|
||||
params.current.item = notebook;
|
||||
setNotes(
|
||||
await db.relations
|
||||
.from(notebook, "note")
|
||||
.selector.grouped(db.settings.getGroupOptions("notes"))
|
||||
);
|
||||
const notes = await db.relations
|
||||
.from(notebook, "note")
|
||||
.selector.grouped(db.settings.getGroupOptions("notes"));
|
||||
setNotes(notes);
|
||||
await notes.item(0, resolveItems);
|
||||
syncWithNavigation();
|
||||
}
|
||||
setLoading(false);
|
||||
@@ -146,13 +161,66 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
id={params.current.item?.id}
|
||||
onPressDefaultRightButton={openEditor}
|
||||
/>
|
||||
<DelayLayout>
|
||||
|
||||
{breadcrumbs ? (
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
paddingHorizontal: 12,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
name="notebook-outline"
|
||||
size={16}
|
||||
customStyle={{ width: 20, height: 25 }}
|
||||
onPress={() => {
|
||||
Navigation.push("Notebooks", {
|
||||
canGoBack: true
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
{breadcrumbs.map((item) => (
|
||||
<PressableButton
|
||||
onPress={async () => {
|
||||
const notebook = await db.notebooks.notebook(item.id);
|
||||
if (!notebook) return;
|
||||
NotebookScreen.navigate(notebook, true);
|
||||
}}
|
||||
key={item.id}
|
||||
customStyle={{
|
||||
width: undefined,
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 0,
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
name="chevron-right"
|
||||
size={16}
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
customStyle={{ width: 20, height: 25 }}
|
||||
/>
|
||||
<Paragraph size={SIZE.xs + 1}>{item.title}</Paragraph>
|
||||
</PressableButton>
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
<DelayLayout wait={loading}>
|
||||
<List
|
||||
data={notes}
|
||||
dataType="note"
|
||||
onRefresh={() => {
|
||||
onRequestUpdate();
|
||||
}}
|
||||
id={params.current.item?.id}
|
||||
renderedInRoute="Notebook"
|
||||
headerTitle={params.current.title}
|
||||
loading={loading}
|
||||
|
||||
@@ -83,7 +83,7 @@ export const Notebooks = ({
|
||||
}}
|
||||
onPressDefaultRightButton={onButtonPress}
|
||||
/>
|
||||
<DelayLayout delay={1}>
|
||||
<DelayLayout>
|
||||
<List
|
||||
data={notebooks}
|
||||
dataType="notebook"
|
||||
|
||||
@@ -38,6 +38,7 @@ import useNavigationStore, {
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { setOnFirstSave } from "./common";
|
||||
import { resolveItems } from "../../components/list/list-item.wrapper";
|
||||
export const WARNING_DATA = {
|
||||
title: "Some notes in this topic are not synced"
|
||||
};
|
||||
@@ -119,7 +120,6 @@ const NotesPage = ({
|
||||
async (data?: NotesScreenParams) => {
|
||||
const isNew = data && data?.item?.id !== params.current?.item?.id;
|
||||
if (data) params.current = data;
|
||||
const { item } = params.current;
|
||||
try {
|
||||
if (isNew) setLoadingNotes(true);
|
||||
const notes = (await get(
|
||||
@@ -127,14 +127,10 @@ const NotesPage = ({
|
||||
true
|
||||
)) as VirtualizedGrouping<Note>;
|
||||
|
||||
if (
|
||||
(item.type === "tag" || item.type === "color") &&
|
||||
(!notes || notes.ids.length === 0)
|
||||
) {
|
||||
return Navigation.goBack();
|
||||
}
|
||||
if (notes.ids.length === 0) setLoadingNotes(false);
|
||||
setNotes(notes);
|
||||
await notes.item(0, resolveItems);
|
||||
setLoadingNotes(false);
|
||||
syncWithNavigation();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -146,8 +142,9 @@ const NotesPage = ({
|
||||
useEffect(() => {
|
||||
if (loadingNotes && !loading) {
|
||||
get(params.current, true)
|
||||
.then((items) => {
|
||||
.then(async (items) => {
|
||||
setNotes(items as VirtualizedGrouping<Note>);
|
||||
await (items as VirtualizedGrouping<Note>).item(0, resolveItems);
|
||||
setLoadingNotes(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
@@ -196,6 +193,7 @@ const NotesPage = ({
|
||||
onRefresh={onRequestUpdate}
|
||||
loading={loading || !isFocused}
|
||||
renderedInRoute={route.name}
|
||||
id={params.current.item?.id}
|
||||
headerTitle={title}
|
||||
customAccentColor={accentColor}
|
||||
placeholder={placeholder}
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
diff --git a/node_modules/recyclerlistview/dist/reactnative/core/layoutmanager/LayoutManager.js b/node_modules/recyclerlistview/dist/reactnative/core/layoutmanager/LayoutManager.js
|
||||
index 9cd3c57..970421a 100644
|
||||
index 9cd3c57..e5bcb69 100644
|
||||
--- a/node_modules/recyclerlistview/dist/reactnative/core/layoutmanager/LayoutManager.js
|
||||
+++ b/node_modules/recyclerlistview/dist/reactnative/core/layoutmanager/LayoutManager.js
|
||||
@@ -111,7 +111,7 @@ var WrapGridLayoutManager = /** @class */ (function (_super) {
|
||||
@@ -7,7 +7,19 @@ index 9cd3c57..970421a 100644
|
||||
var itemRect = null;
|
||||
var oldLayout = null;
|
||||
- for (var i = startIndex; i < itemCount; i++) {
|
||||
+ for (var i = startIndex; i < Math.min(startIndex + 5000, itemCount); i++) {
|
||||
+ for (var i = startIndex; i < Math.min(startIndex + 500, itemCount); i++) {
|
||||
oldLayout = this._layouts[i];
|
||||
var layoutType = this._layoutProvider.getLayoutTypeForIndex(i);
|
||||
if (oldLayout && oldLayout.isOverridden && oldLayout.type === layoutType) {
|
||||
@@ -184,6 +184,11 @@ var WrapGridLayoutManager = /** @class */ (function (_super) {
|
||||
}
|
||||
var i = startIndex - 1;
|
||||
for (; i >= 0; i--) {
|
||||
+
|
||||
+ if (!this._layouts[i]) {
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
if (this._isHorizontal) {
|
||||
if (this._layouts[i].y === 0) {
|
||||
break;
|
||||
|
||||
@@ -36,6 +36,7 @@ const EXTRA_ICON_NAMES = [
|
||||
"star-outline",
|
||||
"link-variant-remove",
|
||||
"link-variant",
|
||||
"link-variant-off",
|
||||
"bell",
|
||||
"bell-off-outline",
|
||||
"check",
|
||||
|
||||
Reference in New Issue
Block a user