mobile: bug fixes

This commit is contained in:
Ammar Ahmed
2023-12-16 11:30:41 +05:00
committed by Abdullah Atta
parent 3502469c1d
commit 787c36c754
22 changed files with 4048 additions and 294 deletions

View File

@@ -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"];

View File

@@ -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>
);

View File

@@ -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;

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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}

View File

@@ -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",

View File

@@ -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,

View File

@@ -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"

View File

@@ -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}

View File

@@ -83,7 +83,7 @@ export const Notebooks = ({
}}
onPressDefaultRightButton={onButtonPress}
/>
<DelayLayout delay={1}>
<DelayLayout>
<List
data={notebooks}
dataType="notebook"

View File

@@ -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}

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View File

@@ -36,6 +36,7 @@ const EXTRA_ICON_NAMES = [
"star-outline",
"link-variant-remove",
"link-variant",
"link-variant-off",
"bell",
"bell-off-outline",
"check",