-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Mobile: Remove redundant navigation history when notes or folders are deleted #13428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Mobile: Remove redundant navigation history when notes or folders are deleted #13428
Conversation
| // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||
| function removeAdjacentNoteDuplicates(items: any[]) { | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||
| return items.filter((item: any, idx: number) => (idx >= 1) ? !(items[idx - 1].routeName === 'Note' && items[idx - 1].noteId === item.noteId) : true); | ||
| } | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||
| function removeAdjacentFolderDuplicates(items: any[]) { | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||
| return items.filter((item: any, idx: number) => (idx >= 1) ? !(items[idx - 1].routeName === 'Notes' && items[idx - 1].folderId === item.folderId) : true); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that necessary the eslint-disable-next-line comments? If it is, and refactoring would be complicated, at least please set the comment correctly as this is not old code. Comment can be eg "assigning types to these variables would be too big of a refactoring"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, they are needed. I've updated the comments
| case 'FOLDER_DELETE': | ||
|
|
||
| { | ||
| let newNavHistoryForFolder = navHistory.filter(route => !(route.routeName === 'Notes' && route.folderId === action.id)); | ||
| newNavHistoryForFolder = removeAdjacentFolderDuplicates(newNavHistoryForFolder); | ||
| navHistory.splice(0, navHistory.length, ...newNavHistoryForFolder); | ||
| } | ||
|
|
||
| break; | ||
|
|
||
| case 'NOTE_DELETE': | ||
|
|
||
| { | ||
| let newNavHistory = navHistory.filter(route => !(route.routeName === 'Note' && route.noteId === action.id)); | ||
| newNavHistory = removeAdjacentNoteDuplicates(newNavHistory); | ||
|
|
||
| // Fix the case where after deletion the currently selected note is also the latest in history | ||
| if (newNavHistory.length && newNavHistory[newNavHistory.length - 1].noteId === state.route.noteId) { | ||
| newNavHistory = newNavHistory.slice(0, newNavHistory.length - 1); | ||
| } | ||
|
|
||
| navHistory.splice(0, navHistory.length, ...newNavHistory); | ||
| } | ||
|
|
||
| break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand why this code is here. It's called FOLDER/NOTE_DELETE but it doesn't delete any note or folder. I guess it's because something else (probably in lib/reducer?) performs the actual deletion? And is it not possible to have this logic in lib/reducer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code needs to be here because this is where the state of the navigation history is stored for mobile. Reducer.ts basically does the same as what I have written here (also does not perform the actual deletion) and in the same way that needs to be there because it's where the state of the navigation history of the desktop app is
The Joplin Data API allows permanently deleting notes and folders. In the desktop app, it correctly handles removing deleted notes and folders from the navigation history when this is done, via the 'FOLDER_DELETE' and 'NOTE_DELETE' event handlers in reducer.ts. This however only applies to the desktop app, and equivalent logic is missing in appReducer.ts which is used to handle the note navigation history on the mobile app. This means that when making such deletions via the API, it can break the navigation history on mobile, causing the back button to navigate to useless / empty screens. It may also happen for other reasons, such as if the sync runs while editing note, and the user has not yet synced some incoming deletions. This PR implements equivalent handling on the mobile app.
Testing
In order to test this change, I have have made local modifications to the WIP Secure Notes plugin, in order to invoke all of possible scenarios which new logic has been added for.
Testing for the FOLDER_DELETE event:
This was done via the following plugin code:
The video shows that when navigating between Test1 > test > Test1 that upon encrypting / decrypting a note (which triggers the above code), when the test folder is deleted, the test folder is removed from the 3 navigation entries, and then Test1 > Test1 is de-duplicated so that pressing the back button just once after exiting the note, navigates back to the starting 'All Notes' folder. The deletion of the temp note was done via the deletion of the tempFolder, where it's children are implicitly deleted, and this fires a NOTE_DELETE event which removes the tempNote navigation's made by the code. Then the other 2 navigations are deduplicated because they are now adjacent, and the remaining entry is removed because it is the current note. Therefore a single press of the back button after encrypt / decrypt will take you back to the the note list
folder.test.mp4
So this test actually covers all the NOTE_DELETE scenarios as well, but I also did a separate test for the NOTE_DELETE scenarios in isolation.
Testing for the NOTE_DELETE event:
This was done via the following plugin code:
note.test.mp4