Skip to content

Commit

Permalink
mobile: multi-tab support
Browse files Browse the repository at this point in the history
  • Loading branch information
ammarahm-ed committed Oct 3, 2024
1 parent 478f51c commit c0792de
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 54 deletions.
9 changes: 4 additions & 5 deletions apps/mobile/app/components/attachments/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,18 +181,17 @@ const Actions = ({
relations
.map((relation) => relation.fromId)
.forEach(async (id) => {
const tab = useTabStore.getState().getTabForNote(id);
if (tab !== undefined) {
const isFocused = useTabStore.getState().currentTab === tab;
useTabStore.getState().forEachNoteTab(id, async (tab) => {
const isFocused = useTabStore.getState().currentTab === tab.id;
if (isFocused) {
eSendEvent(eOnLoadNote, {
item: await db.notes.note(id),
forced: true
});
} else {
editorController.current.commands.setLoading(true, tab);
editorController.current.commands.setLoading(true, tab.id);
}
}
});
});
close?.();
},
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/app/components/properties/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
close();
eSendEvent(eOnLoadNote, {
item: item,
presistTab: true
newTab: true
});
if (!DDS.isTab) {
tabBarRef.current?.goToPage(1);
Expand Down
24 changes: 10 additions & 14 deletions apps/mobile/app/hooks/use-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable no-inner-declarations */
import { VAULT_ERRORS } from "@notesnook/core";
import {
Color,
createInternalLink,
ItemReference,
Note,
Notebook,
Reminder,
Tag,
TrashItem
TrashItem,
VAULT_ERRORS
} from "@notesnook/core";
import { DisplayedNotification } from "@notifee/react-native";
import Clipboard from "@react-native-clipboard/clipboard";
Expand All @@ -39,18 +40,20 @@ import NoteHistory from "../components/note-history";
import { AddNotebookSheet } from "../components/sheets/add-notebook";
import MoveNoteSheet from "../components/sheets/add-to";
import ExportNotesSheet from "../components/sheets/export-notes";
import { MoveNotebookSheet } from "../components/sheets/move-notebook";
import { MoveNotes } from "../components/sheets/move-notes/movenote";
import PublishNoteSheet from "../components/sheets/publish-note";
import { ReferencesList } from "../components/sheets/references";
import { RelationsList } from "../components/sheets/relations-list/index";
import ReminderSheet from "../components/sheets/reminder";
import { useSideBarDraggingStore } from "../components/side-menu/dragging-store";
import { useTabStore } from "../screens/editor/tiptap/use-tab-store";
import {
ToastManager,
eSendEvent,
eSubscribeEvent,
openVault,
presentSheet
presentSheet,
ToastManager
} from "../services/event-manager";
import Navigation from "../services/navigation";
import Notifications from "../services/notifications";
Expand All @@ -60,14 +63,10 @@ import { useRelationStore } from "../stores/use-relation-store";
import { useSelectionStore } from "../stores/use-selection-store";
import { useTagStore } from "../stores/use-tag-store";
import { useUserStore } from "../stores/use-user-store";
import Errors from "../utils/errors";
import { eOpenLoginDialog, eUpdateNoteInEditor } from "../utils/events";
import { deleteItems } from "../utils/functions";
import { convertNoteToText } from "../utils/note-to-text";
import { sleep } from "../utils/time";
import { ReferencesList } from "../components/sheets/references";
import { createInternalLink } from "@notesnook/core";
import { MoveNotebookSheet } from "../components/sheets/move-notebook";

export const useActions = ({
close,
Expand Down Expand Up @@ -542,14 +541,11 @@ export const useActions = ({
const toggleReadyOnlyMode = async () => {
const currentReadOnly = (item as Note).readonly;
await db.notes.readonly(!currentReadOnly, item?.id);

if (useTabStore.getState().hasTabForNote(item.id)) {
const tabId = useTabStore.getState().getTabForNote(item.id);
if (!tabId) return;
useTabStore.getState().updateTab(tabId, {
useTabStore.getState().forEachNoteTab(item.id, (tab) => {
useTabStore.getState().updateTab(tab.id, {
readonly: !currentReadOnly
});
}
});
Navigation.queueRoutesForUpdate();
close();
};
Expand Down
17 changes: 9 additions & 8 deletions apps/mobile/app/screens/editor/tiptap/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { sleep } from "../../../utils/time";
import { Settings } from "./types";
import { useTabStore } from "./use-tab-store";
import { getResponse, randId, textInput } from "./utils";
import { EditorSessionItem } from "./tab-history";
import { EditorSessionItem } from "@notesnook/common/dist/utils/editor-sessions";

type Action = { job: string; id: string };

Expand Down Expand Up @@ -217,11 +217,11 @@ if (typeof statusBar !== "undefined") {

setTags = async (note: Note | null | undefined) => {
if (!note) return;
const tabId = useTabStore.getState().getTabForNote(note.id);

const tags = await db.relations.to(note, "tag").resolve();
await this.doAsync(
`
useTabStore.getState().forEachNoteTab(note.id, async (tab) => {
const tabId = tab.id;
const tags = await db.relations.to(note, "tag").resolve();
await this.doAsync(
`
const tags = editorTags[${tabId}];
if (tags && tags.current) {
tags.current.setTags(${JSON.stringify(
Expand All @@ -234,8 +234,9 @@ if (typeof statusBar !== "undefined") {
)});
}
`,
"setTags"
);
"setTags"
);
});
};

clearTags = async (tabId: number) => {
Expand Down
13 changes: 11 additions & 2 deletions apps/mobile/app/screens/editor/tiptap/use-editor-events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -607,10 +607,18 @@ export const useEditorEvents = (
editorMessage.value
);

const { hasContent, isLoading, needsRefresh } = editorMessage.value;

eSendEvent(eEditorTabFocused, editorMessage.tabId);

if (needsRefresh) {
useTabStore.getState().updateTab(editorMessage.tabId, {
needsRefresh: false
});
}

if (
(!editorMessage.value || editor.currentLoadingNoteId.current) &&
(isLoading || !hasContent || needsRefresh) &&
editorMessage.noteId
) {
if (!useSettingStore.getState().isAppLoading) {
Expand All @@ -619,7 +627,8 @@ export const useEditorEvents = (
eSendEvent(eOnLoadNote, {
item: note,
forced: true,
tabId: editorMessage.tabId
tabId: editorMessage.tabId,
refresh: hasContent && needsRefresh ? needsRefresh : false
});
}
} else {
Expand Down
34 changes: 25 additions & 9 deletions apps/mobile/app/screens/editor/tiptap/use-tab-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export type TabItem = {
locked?: boolean;
noteLocked?: boolean;
pinned?: boolean;
needsRefresh?: boolean;
};

const history = new History();
Expand All @@ -95,10 +96,12 @@ export type TabStore = {
) => void;
removeTab: (index: number) => void;
moveTab: (index: number, toIndex: number) => void;
newTab: (options?: Omit<Partial<TabItem>, "id">) => void;
newTab: (options?: Omit<Partial<TabItem>, "id">) => number;
focusTab: (id: number) => void;
getNoteIdForTab: (id: number) => string | undefined;
getTabForNote: (noteId: string) => number | undefined;
getTabsForNote: (noteId: string) => TabItem[];
forEachNoteTab: (noteId: string, cb: (tab: TabItem) => void) => void;
hasTabForNote: (noteId: string) => boolean;
focusEmptyTab: () => void;
getCurrentNoteId: () => string | undefined;
Expand Down Expand Up @@ -230,18 +233,23 @@ export const useTabStore = create<TabStore>(
const nextTabs = get().tabs.slice();
nextTabs.splice(index, 1);
history.remove(id);
if (nextTabs.length === 0) {
nextTabs.push({
id: 0
});
}
tabHistory.clearStackForTab(id);
set({
tabs: nextTabs
});
get().focusTab(
isFocused ? history.restoreLast() || 0 : get().currentTab
);
syncTabs("tabs");
setTimeout(() => {
if (nextTabs.length === 0) {
set({
tabs: [{ id: 0 }]
});
get().focusTab(0);
} else {
get().focusTab(
isFocused ? history.restoreLast() || 0 : get().currentTab
);
}
});
}
},
newTab: (options) => {
Expand All @@ -262,6 +270,7 @@ export const useTabStore = create<TabStore>(
tabs: nextTabs
});
get().focusTab(id);
return id;
},
focusEmptyTab: () => {
const index = get().tabs.findIndex((t) => !t.noteId);
Expand Down Expand Up @@ -307,6 +316,13 @@ export const useTabStore = create<TabStore>(
getTabForNote: (noteId: string) => {
return get().tabs.find((t) => t.noteId === noteId)?.id;
},
getTabsForNote(noteId: string) {
return get().tabs.filter((t) => t.noteId === noteId);
},
forEachNoteTab: (noteId: string, cb: (tab: TabItem) => void) => {
const tabs = get().tabs.filter((t) => t.noteId === noteId);
tabs.forEach(cb);
},
getCurrentNoteId: () => {
return get().tabs.find((t) => t.id === get().currentTab)?.noteId;
},
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/app/services/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ async function loadNote(id: string, jump: boolean) {
if (tab !== undefined) {
useTabStore.getState().focusTab(tab);
} else {
useTabStore.getState().focusPreviewTab(id, {
useTabStore.getState().updateTab(useTabStore.getState().currentTab, {
noteId: id,
readonly: note.readonly,
noteLocked: isLocked
Expand Down
9 changes: 7 additions & 2 deletions packages/editor-mobile/src/components/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,13 @@ const Tiptap = ({

post(
EditorEvents.tabFocused,
!!globalThis.editorControllers[tabRef.current.id]?.content.current &&
!editorControllers[tabRef.current.id]?.loading,
{
hasContent:
!!globalThis.editorControllers[tabRef.current.id]?.content
.current,
isLoading: editorControllers[tabRef.current.id]?.loading,
needsRefresh: tabRef.current?.needsRefresh
},
tabRef.current.id,
state.getCurrentNoteId()
);
Expand Down
25 changes: 13 additions & 12 deletions packages/editor-mobile/src/hooks/useEditorController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import {
useState
} from "react";
import { getRoot, post, postAsyncWithTimeout, saveTheme } from "../utils";
import { EditorEvents } from "../utils/editor-events";
import { injectCss, transform } from "../utils/css";
import { EditorEvents } from "../utils/editor-events";
import { pendingSaveRequests } from "../utils/pending-saves";
import { useTabContext, useTabStore } from "./useTabStore";

Expand Down Expand Up @@ -130,7 +130,7 @@ export function useEditorController({
const tabRef = useRef(tab);
tabRef.current = tab;

const [loading, setLoading] = useState(true);
const [loading, setLoading] = useState(false);
const setTheme = useThemeEngineStore((store) => store.setTheme);
const { colors } = useThemeColors("editor");
const [title, setTitle] = useState("");
Expand Down Expand Up @@ -229,18 +229,18 @@ export function useEditorController({
clearTimeout(timers.current?.change);
}

const params = [
{
html: htmlContentRef.current,
ignoreEdit: ignoreEdit
},
tabRef.current.id,
tabRef.current.noteId,
currentSessionId
];

timers.current.change = setTimeout(async () => {
htmlContentRef.current = editor.getHTML();
const params = [
{
html: htmlContentRef.current,
ignoreEdit: ignoreEdit
},
tabRef.current.id,
tabRef.current.noteId,
currentSessionId
];

const pendingContentIds =
await pendingSaveRequests.getPendingContentIds();
postAsyncWithTimeout(EditorEvents.content, ...params, 5000)
Expand Down Expand Up @@ -350,6 +350,7 @@ export function useEditorController({
}

scrollTo?.(noteState?.top || 0);
setLoading(false);
countWords(0);
}

Expand Down
1 change: 1 addition & 0 deletions packages/editor-mobile/src/hooks/useTabStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export type TabItem = {
locked?: boolean;
noteLocked?: boolean;
pinned?: boolean;
needsRefresh?: boolean;
};

export type NoteState = {
Expand Down

0 comments on commit c0792de

Please sign in to comment.