From 7c7c1b9f90773bca337c5fb93da1dc4fadd77ad1 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 14 May 2024 10:19:18 -0700 Subject: [PATCH 1/5] Desktop: Fixes #10230: Fix new note and to-do buttons greyed when initial selection is all notes/a tag --- packages/app-desktop/app.ts | 4 ++++ .../app-mobile/components/screens/Notes.tsx | 23 +++---------------- packages/app-mobile/root.tsx | 4 ++++ packages/lib/reducer.ts | 6 +++++ 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/packages/app-desktop/app.ts b/packages/app-desktop/app.ts index d49ca86e105..6f8d41559c0 100644 --- a/packages/app-desktop/app.ts +++ b/packages/app-desktop/app.ts @@ -513,6 +513,10 @@ class Application extends BaseApplication { }); } + this.store().dispatch({ + type: 'INITIAL_SELECTION_SET', + }); + this.store().dispatch({ type: 'FOLDER_SET_COLLAPSED_ALL', ids: Setting.value('collapsedFolderIds'), diff --git a/packages/app-mobile/components/screens/Notes.tsx b/packages/app-mobile/components/screens/Notes.tsx index ce440735cf9..4de1ab756aa 100644 --- a/packages/app-mobile/components/screens/Notes.tsx +++ b/packages/app-mobile/components/screens/Notes.tsx @@ -18,7 +18,6 @@ const { BackButtonService } = require('../../services/back-button.js'); import { AppState } from '../../utils/types'; import { NoteEntity } from '@joplin/lib/services/database/types'; import { itemIsInTrash } from '@joplin/lib/services/trash'; -const { ALL_NOTES_FILTER_ID } = require('@joplin/lib/reserved-ids.js'); // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied class NotesScreenComponent extends BaseScreenComponent { @@ -230,34 +229,19 @@ class NotesScreenComponent extends BaseScreenComponent { let buttonFolderId = this.props.selectedFolderId !== Folder.conflictFolderId() ? this.props.selectedFolderId : null; if (!buttonFolderId) buttonFolderId = this.props.activeFolderId; - const isAllNotes = - this.props.notesParentType === 'SmartFilter' - && this.props.selectedSmartFilterId === ALL_NOTES_FILTER_ID; - - // Usually, when showing all notes, activeFolderId/selectedFolderId is set to the last - // active folder. - // If the app starts showing all notes, activeFolderId/selectedFolderId are - // empty or null. As such, we need a special case to show the buttons: - const addFolderNoteButtons = !!buttonFolderId || isAllNotes; + const addFolderNoteButtons = !!buttonFolderId; const thisComp = this; const makeActionButtonComp = () => { if ((this.props.notesParentType === 'Folder' && itemIsInTrash(parent)) || !Folder.atLeastOneRealFolderExists(this.props.folders)) return null; - const getTargetFolderId = async () => { - if (!buttonFolderId && isAllNotes) { - return (await Folder.defaultFolder()).id; - } - return buttonFolderId; - }; if (addFolderNoteButtons && this.props.folders.length > 0) { const buttons = []; buttons.push({ label: _('New to-do'), onPress: async () => { - const folderId = await getTargetFolderId(); const isTodo = true; - void this.newNoteNavigate(folderId, isTodo); + void this.newNoteNavigate(buttonFolderId, isTodo); }, color: '#9b59b6', icon: 'checkbox-outline', @@ -266,9 +250,8 @@ class NotesScreenComponent extends BaseScreenComponent { buttons.push({ label: _('New note'), onPress: async () => { - const folderId = await getTargetFolderId(); const isTodo = false; - void this.newNoteNavigate(folderId, isTodo); + void this.newNoteNavigate(buttonFolderId, isTodo); }, color: '#9b59b6', icon: 'document', diff --git a/packages/app-mobile/root.tsx b/packages/app-mobile/root.tsx index 5b42946c35a..5aa1f21d892 100644 --- a/packages/app-mobile/root.tsx +++ b/packages/app-mobile/root.tsx @@ -710,6 +710,10 @@ async function initialize(dispatch: Function) { }); } + this.store().dispatch({ + type: 'INITIAL_SELECTION_SET', + }); + await clearSharedFilesCache(); } catch (error) { alert(`Initialization error: ${error.message}`); diff --git a/packages/lib/reducer.ts b/packages/lib/reducer.ts index cd7f632c0f6..fa95516395b 100644 --- a/packages/lib/reducer.ts +++ b/packages/lib/reducer.ts @@ -883,6 +883,12 @@ const reducer = produce((draft: Draft = defaultState, action: any) => { break; } + case 'INITIAL_SELECTION_SET': + // To allow creating notes when opening the app with all notes and/or tags, + // we also need a "last selected folder ID". + draft.selectedFolderId ??= draft.settings.activeFolderId; + break; + case 'SMART_FILTER_SELECT': draft.notesParentType = 'SmartFilter'; draft.selectedSmartFilterId = action.id; From 43f673b110ba3aa5f8237e98ec8ce117c6907f3c Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 14 May 2024 10:37:41 -0700 Subject: [PATCH 2/5] Fix mobile startup --- packages/app-mobile/root.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app-mobile/root.tsx b/packages/app-mobile/root.tsx index 5aa1f21d892..514b5dc3634 100644 --- a/packages/app-mobile/root.tsx +++ b/packages/app-mobile/root.tsx @@ -710,7 +710,7 @@ async function initialize(dispatch: Function) { }); } - this.store().dispatch({ + dispatch({ type: 'INITIAL_SELECTION_SET', }); From f00c02dad92bf77a8dddc41dd4bbbfad2a853c11 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 14 May 2024 10:49:53 -0700 Subject: [PATCH 3/5] Fix mobile default folder --- packages/app-mobile/root.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/app-mobile/root.tsx b/packages/app-mobile/root.tsx index 514b5dc3634..727b0432cff 100644 --- a/packages/app-mobile/root.tsx +++ b/packages/app-mobile/root.tsx @@ -215,7 +215,9 @@ const generalMiddleware = (store: any) => (next: any) => async (action: any) => } if (action.type === 'NAV_GO' && action.routeName === 'Notes') { - Setting.setValue('activeFolderId', newState.selectedFolderId); + if (newState.selectedFolderId) { + Setting.setValue('activeFolderId', newState.selectedFolderId); + } const notesParent: NotesParent = { type: action.smartFilterId ? 'SmartFilter' : 'Folder', selectedItemId: action.smartFilterId ? action.smartFilterId : newState.selectedFolderId, From a7efc802dbaa6c11c30842dc59f7be0aa964a47e Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Wed, 15 May 2024 23:05:24 -0700 Subject: [PATCH 4/5] Mobile: Fix new note button on new profile --- packages/app-mobile/root.tsx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/app-mobile/root.tsx b/packages/app-mobile/root.tsx index 727b0432cff..99a2fc53454 100644 --- a/packages/app-mobile/root.tsx +++ b/packages/app-mobile/root.tsx @@ -215,9 +215,10 @@ const generalMiddleware = (store: any) => (next: any) => async (action: any) => } if (action.type === 'NAV_GO' && action.routeName === 'Notes') { - if (newState.selectedFolderId) { + if ('selectedFolderId' in newState) { Setting.setValue('activeFolderId', newState.selectedFolderId); } + const notesParent: NotesParent = { type: action.smartFilterId ? 'SmartFilter' : 'Folder', selectedItemId: action.smartFilterId ? action.smartFilterId : newState.selectedFolderId, @@ -471,6 +472,21 @@ const initializeTempDir = async () => { return tempDir; }; +const getInitialActiveFolder = async () => { + let folderId = Setting.value('activeFolderId'); + + // In some cases (e.g. new profile/install), activeFolderId hasn't been set yet. + // Because activeFolderId is used to determine the parent for new notes, initialize + // it here: + if (!folderId) { + folderId = (await Folder.defaultFolder())?.id; + if (folderId) { + Setting.setValue('activeFolderId', folderId); + } + } + return await Folder.load(folderId); +}; + // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied async function initialize(dispatch: Function) { shimInit(); @@ -688,10 +704,7 @@ async function initialize(dispatch: Function) { // items: masterKeys, // }); - const folderId = Setting.value('activeFolderId'); - let folder = await Folder.load(folderId); - - if (!folder) folder = await Folder.defaultFolder(); + const folder = await getInitialActiveFolder(); dispatch({ type: 'FOLDER_SET_COLLAPSED_ALL', From ad1c336f98ba849fd3b7e39f2c5c1f3239565399 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Thu, 23 May 2024 06:44:34 -0700 Subject: [PATCH 5/5] Use SETTING_UPDATE_* instead of new INITIAL_SELECTION_SET event --- packages/app-desktop/app.ts | 4 ---- packages/app-mobile/root.tsx | 4 ---- packages/lib/reducer.ts | 12 ++++++------ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/app-desktop/app.ts b/packages/app-desktop/app.ts index 6f8d41559c0..d49ca86e105 100644 --- a/packages/app-desktop/app.ts +++ b/packages/app-desktop/app.ts @@ -513,10 +513,6 @@ class Application extends BaseApplication { }); } - this.store().dispatch({ - type: 'INITIAL_SELECTION_SET', - }); - this.store().dispatch({ type: 'FOLDER_SET_COLLAPSED_ALL', ids: Setting.value('collapsedFolderIds'), diff --git a/packages/app-mobile/root.tsx b/packages/app-mobile/root.tsx index 99a2fc53454..89152df1a81 100644 --- a/packages/app-mobile/root.tsx +++ b/packages/app-mobile/root.tsx @@ -725,10 +725,6 @@ async function initialize(dispatch: Function) { }); } - dispatch({ - type: 'INITIAL_SELECTION_SET', - }); - await clearSharedFilesCache(); } catch (error) { alert(`Initialization error: ${error.message}`); diff --git a/packages/lib/reducer.ts b/packages/lib/reducer.ts index fa95516395b..0e9823b0915 100644 --- a/packages/lib/reducer.ts +++ b/packages/lib/reducer.ts @@ -883,12 +883,6 @@ const reducer = produce((draft: Draft = defaultState, action: any) => { break; } - case 'INITIAL_SELECTION_SET': - // To allow creating notes when opening the app with all notes and/or tags, - // we also need a "last selected folder ID". - draft.selectedFolderId ??= draft.settings.activeFolderId; - break; - case 'SMART_FILTER_SELECT': draft.notesParentType = 'SmartFilter'; draft.selectedSmartFilterId = action.id; @@ -1341,6 +1335,12 @@ const reducer = produce((draft: Draft = defaultState, action: any) => { handleHistory(draft, action); } + if (action.type === 'SETTING_UPDATE_ALL' || (action.type === 'SETTING_UPDATE_ONE' && action.key === 'activeFolderId')) { + // To allow creating notes when opening the app with all notes and/or tags, + // a "last selected folder ID" needs to be set. + draft.selectedFolderId ??= draft.settings.activeFolderId; + } + for (const additionalReducer of additionalReducers) { additionalReducer.reducer(draft, action); }