From 218e7a3d069e037005837f63e2f504900ea35c8e Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Mon, 6 Jun 2022 23:50:11 +0530 Subject: [PATCH] feat: add files button to multiple selection view (#1067) --- .../ApplicationView/ApplicationView.tsx | 7 +- .../AttachedFilesButton.tsx | 28 ++++--- .../FileView/FileViewWithoutProtection.tsx | 1 + .../MultipleSelectedFiles.tsx | 32 +++++++- .../MultipleSelectedNotes.tsx | 54 ++++++++++++-- .../NoteGroupView/NoteGroupView.tsx | 16 +++- .../Components/NoteView/NoteView.tsx | 7 +- .../NotesContextMenu/NotesContextMenu.tsx | 30 +++++--- .../Components/NotesOptions/AddTagOption.tsx | 22 +++--- .../NotesOptions/ChangeEditorOption.tsx | 2 - .../Components/NotesOptions/NotesOptions.tsx | 73 +++++++++++-------- .../NotesOptions/NotesOptionsPanel.tsx | 20 ++++- .../NotesOptions/NotesOptionsProps.ts | 8 +- .../PinNoteButton/PinNoteButton.tsx | 18 ++--- 14 files changed, 222 insertions(+), 96 deletions(-) diff --git a/app/assets/javascripts/Components/ApplicationView/ApplicationView.tsx b/app/assets/javascripts/Components/ApplicationView/ApplicationView.tsx index cd3d0086ee5..558b6bd7787 100644 --- a/app/assets/javascripts/Components/ApplicationView/ApplicationView.tsx +++ b/app/assets/javascripts/Components/ApplicationView/ApplicationView.tsx @@ -191,7 +191,12 @@ const ApplicationView: FunctionComponent = ({ application, mainApplicatio {renderChallenges()} <> - + Promise } @@ -36,8 +38,12 @@ const AttachedFilesButton: FunctionComponent = ({ filePreviewModalController, navigationController, notesController, + selectionController, onClickPreprocessing, }: Props) => { + const { allFiles, attachedFiles } = filesController + const attachedFilesCount = attachedFiles.length + const premiumModal = usePremiumModal() const note: SNNote | undefined = notesController.firstSelectedNote @@ -63,22 +69,14 @@ const AttachedFilesButton: FunctionComponent = ({ const [currentTab, setCurrentTab] = useState( navigationController.isInFilesView ? PopoverTabs.AllFiles : PopoverTabs.AttachedFiles, ) - const [allFiles, setAllFiles] = useState([]) - const [attachedFiles, setAttachedFiles] = useState([]) - const attachedFilesCount = attachedFiles.length - useEffect(() => { - const unregisterFileStream = application.streamItems(ContentType.File, () => { - setAllFiles(application.items.getDisplayableFiles()) - if (note) { - setAttachedFiles(application.items.getFilesForNote(note)) - } - }) + const isAttachedTabDisabled = navigationController.isInFilesView || selectionController.selectedItemsCount > 1 - return () => { - unregisterFileStream() + useEffect(() => { + if (isAttachedTabDisabled && currentTab === PopoverTabs.AttachedFiles) { + setCurrentTab(PopoverTabs.AllFiles) } - }, [application, note]) + }, [currentTab, isAttachedTabDisabled]) const toggleAttachedFilesMenu = useCallback(async () => { const rect = buttonRef.current?.getBoundingClientRect() @@ -304,7 +302,7 @@ const AttachedFilesButton: FunctionComponent = ({ currentTab={currentTab} isDraggingFiles={isDraggingFiles} setCurrentTab={setCurrentTab} - attachedTabDisabled={navigationController.isInFilesView} + attachedTabDisabled={isAttachedTabDisabled} /> )} diff --git a/app/assets/javascripts/Components/FileView/FileViewWithoutProtection.tsx b/app/assets/javascripts/Components/FileView/FileViewWithoutProtection.tsx index ff260248ae6..c8d146017ca 100644 --- a/app/assets/javascripts/Components/FileView/FileViewWithoutProtection.tsx +++ b/app/assets/javascripts/Components/FileView/FileViewWithoutProtection.tsx @@ -57,6 +57,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }: filesController={viewControllerManager.filesController} navigationController={viewControllerManager.navigationController} notesController={viewControllerManager.notesController} + selectionController={viewControllerManager.selectionController} /> { +const MultipleSelectedFiles = ({ + application, + filesController, + featuresController, + filePreviewModalController, + navigationController, + notesController, + selectionController, +}: Props) => { const count = selectionController.selectedFilesCount const cancelMultipleSelection = useCallback(() => { @@ -23,6 +42,17 @@ const MultipleSelectedFiles = ({ filesController, selectionController }: Props)

{count} selected files

+
+ +
diff --git a/app/assets/javascripts/Components/MultipleSelectedNotes/MultipleSelectedNotes.tsx b/app/assets/javascripts/Components/MultipleSelectedNotes/MultipleSelectedNotes.tsx index 60b482fd65c..7d3949034ac 100644 --- a/app/assets/javascripts/Components/MultipleSelectedNotes/MultipleSelectedNotes.tsx +++ b/app/assets/javascripts/Components/MultipleSelectedNotes/MultipleSelectedNotes.tsx @@ -1,4 +1,3 @@ -import { ViewControllerManager } from '@/Services/ViewControllerManager' import { IlNotesIcon } from '@standardnotes/icons' import { observer } from 'mobx-react-lite' import NotesOptionsPanel from '@/Components/NotesOptions/NotesOptionsPanel' @@ -6,18 +5,41 @@ import { WebApplication } from '@/Application/Application' import PinNoteButton from '@/Components/PinNoteButton/PinNoteButton' import Button from '../Button/Button' import { useCallback } from 'react' +import AttachedFilesButton from '../AttachedFilesPopover/AttachedFilesButton' +import { FeaturesController } from '@/Controllers/FeaturesController' +import { FilePreviewModalController } from '@/Controllers/FilePreviewModalController' +import { FilesController } from '@/Controllers/FilesController' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' +import { NotesController } from '@/Controllers/NotesController' +import { SelectedItemsController } from '@/Controllers/SelectedItemsController' +import { NoteTagsController } from '@/Controllers/NoteTagsController' type Props = { application: WebApplication - viewControllerManager: ViewControllerManager + featuresController: FeaturesController + filePreviewModalController: FilePreviewModalController + filesController: FilesController + navigationController: NavigationController + notesController: NotesController + noteTagsController: NoteTagsController + selectionController: SelectedItemsController } -const MultipleSelectedNotes = ({ application, viewControllerManager }: Props) => { - const count = viewControllerManager.notesController.selectedNotesCount +const MultipleSelectedNotes = ({ + application, + featuresController, + filePreviewModalController, + filesController, + navigationController, + notesController, + noteTagsController, + selectionController, +}: Props) => { + const count = notesController.selectedNotesCount const cancelMultipleSelection = useCallback(() => { - viewControllerManager.selectionController.cancelMultipleSelection() - }, [viewControllerManager]) + selectionController.cancelMultipleSelection() + }, [selectionController]) return (
@@ -25,9 +47,25 @@ const MultipleSelectedNotes = ({ application, viewControllerManager }: Props) =>

{count} selected notes

- +
- +
+ +
+
diff --git a/app/assets/javascripts/Components/NoteGroupView/NoteGroupView.tsx b/app/assets/javascripts/Components/NoteGroupView/NoteGroupView.tsx index cb4477dd748..210611228a4 100644 --- a/app/assets/javascripts/Components/NoteGroupView/NoteGroupView.tsx +++ b/app/assets/javascripts/Components/NoteGroupView/NoteGroupView.tsx @@ -83,13 +83,27 @@ class NoteGroupView extends PureComponent { return (
{this.state.showMultipleSelectedNotes && ( - + )} {this.state.showMultipleSelectedFiles && ( )} diff --git a/app/assets/javascripts/Components/NoteView/NoteView.tsx b/app/assets/javascripts/Components/NoteView/NoteView.tsx index 4be1b1ba212..2c8f6930327 100644 --- a/app/assets/javascripts/Components/NoteView/NoteView.tsx +++ b/app/assets/javascripts/Components/NoteView/NoteView.tsx @@ -950,6 +950,7 @@ class NoteView extends PureComponent { filesController={this.viewControllerManager.filesController} navigationController={this.viewControllerManager.navigationController} notesController={this.viewControllerManager.notesController} + selectionController={this.viewControllerManager.selectionController} />
@@ -961,13 +962,15 @@ class NoteView extends PureComponent {
diff --git a/app/assets/javascripts/Components/NotesContextMenu/NotesContextMenu.tsx b/app/assets/javascripts/Components/NotesContextMenu/NotesContextMenu.tsx index edb2f4df736..6c63c08bc64 100644 --- a/app/assets/javascripts/Components/NotesContextMenu/NotesContextMenu.tsx +++ b/app/assets/javascripts/Components/NotesContextMenu/NotesContextMenu.tsx @@ -1,29 +1,31 @@ -import { ViewControllerManager } from '@/Services/ViewControllerManager' import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur' import { useCloseOnClickOutside } from '@/Hooks/useCloseOnClickOutside' import { observer } from 'mobx-react-lite' import NotesOptions from '@/Components/NotesOptions/NotesOptions' import { useCallback, useEffect, useRef } from 'react' import { WebApplication } from '@/Application/Application' +import { NotesController } from '@/Controllers/NotesController' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' +import { NoteTagsController } from '@/Controllers/NoteTagsController' type Props = { application: WebApplication - viewControllerManager: ViewControllerManager + navigationController: NavigationController + notesController: NotesController + noteTagsController: NoteTagsController } -const NotesContextMenu = ({ application, viewControllerManager }: Props) => { - const { contextMenuOpen, contextMenuPosition, contextMenuMaxHeight } = viewControllerManager.notesController +const NotesContextMenu = ({ application, navigationController, notesController, noteTagsController }: Props) => { + const { contextMenuOpen, contextMenuPosition, contextMenuMaxHeight } = notesController const contextMenuRef = useRef(null) - const [closeOnBlur] = useCloseOnBlur(contextMenuRef, (open: boolean) => - viewControllerManager.notesController.setContextMenuOpen(open), - ) + const [closeOnBlur] = useCloseOnBlur(contextMenuRef, (open: boolean) => notesController.setContextMenuOpen(open)) - useCloseOnClickOutside(contextMenuRef, () => viewControllerManager.notesController.setContextMenuOpen(false)) + useCloseOnClickOutside(contextMenuRef, () => notesController.setContextMenuOpen(false)) const reloadContextMenuLayout = useCallback(() => { - viewControllerManager.notesController.reloadContextMenuLayout() - }, [viewControllerManager]) + notesController.reloadContextMenuLayout() + }, [notesController]) useEffect(() => { window.addEventListener('resize', reloadContextMenuLayout) @@ -41,7 +43,13 @@ const NotesContextMenu = ({ application, viewControllerManager }: Props) => { maxHeight: contextMenuMaxHeight, }} > - + ) : null } diff --git a/app/assets/javascripts/Components/NotesOptions/AddTagOption.tsx b/app/assets/javascripts/Components/NotesOptions/AddTagOption.tsx index 764e46c2002..9a8a481d78d 100644 --- a/app/assets/javascripts/Components/NotesOptions/AddTagOption.tsx +++ b/app/assets/javascripts/Components/NotesOptions/AddTagOption.tsx @@ -1,16 +1,20 @@ -import { ViewControllerManager } from '@/Services/ViewControllerManager' import { calculateSubmenuStyle, SubmenuStyle } from '@/Utils/CalculateSubmenuStyle' import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure' import { observer } from 'mobx-react-lite' import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react' import Icon from '@/Components/Icon/Icon' import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' +import { NotesController } from '@/Controllers/NotesController' +import { NoteTagsController } from '@/Controllers/NoteTagsController' type Props = { - viewControllerManager: ViewControllerManager + navigationController: NavigationController + notesController: NotesController + noteTagsController: NoteTagsController } -const AddTagOption: FunctionComponent = ({ viewControllerManager }) => { +const AddTagOption: FunctionComponent = ({ navigationController, notesController, noteTagsController }) => { const menuContainerRef = useRef(null) const menuRef = useRef(null) const menuButtonRef = useRef(null) @@ -84,22 +88,22 @@ const AddTagOption: FunctionComponent = ({ viewControllerManager }) => { }} className="sn-dropdown min-w-80 flex flex-col py-2 max-h-120 max-w-xs fixed overflow-y-auto" > - {viewControllerManager.navigationController.tags.map((tag) => ( + {navigationController.tags.map((tag) => ( ))} diff --git a/app/assets/javascripts/Components/NotesOptions/ChangeEditorOption.tsx b/app/assets/javascripts/Components/NotesOptions/ChangeEditorOption.tsx index 3cfcd5c652a..8556b542456 100644 --- a/app/assets/javascripts/Components/NotesOptions/ChangeEditorOption.tsx +++ b/app/assets/javascripts/Components/NotesOptions/ChangeEditorOption.tsx @@ -1,6 +1,5 @@ import { KeyboardKey } from '@/Services/IOService' import { WebApplication } from '@/Application/Application' -import { ViewControllerManager } from '@/Services/ViewControllerManager' import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure' import { SNNote } from '@standardnotes/snjs' import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react' @@ -10,7 +9,6 @@ import { calculateSubmenuStyle, SubmenuStyle } from '@/Utils/CalculateSubmenuSty import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur' type ChangeEditorOptionProps = { - viewControllerManager: ViewControllerManager application: WebApplication note: SNNote } diff --git a/app/assets/javascripts/Components/NotesOptions/NotesOptions.tsx b/app/assets/javascripts/Components/NotesOptions/NotesOptions.tsx index 8e20dac52c6..5d3de8c5ddd 100644 --- a/app/assets/javascripts/Components/NotesOptions/NotesOptions.tsx +++ b/app/assets/javascripts/Components/NotesOptions/NotesOptions.tsx @@ -1,9 +1,8 @@ -import { ViewControllerManager } from '@/Services/ViewControllerManager' import Icon from '@/Components/Icon/Icon' import Switch from '@/Components/Switch/Switch' import { observer } from 'mobx-react-lite' import { useState, useEffect, useMemo, useCallback, FunctionComponent } from 'react' -import { SNApplication, SNNote } from '@standardnotes/snjs' +import { SNApplication, SNComponent, SNNote } from '@standardnotes/snjs' import { KeyboardModifier } from '@/Services/IOService' import ChangeEditorOption from './ChangeEditorOption' import { BYTES_IN_ONE_MEGABYTE } from '@/Constants/Constants' @@ -11,6 +10,7 @@ import ListedActionsOption from './ListedActionsOption' import AddTagOption from './AddTagOption' import { addToast, dismissToast, ToastType } from '@standardnotes/stylekit' import { NotesOptionsProps } from './NotesOptionsProps' +import { NotesController } from '@/Controllers/NotesController' type DeletePermanentlyButtonProps = { closeOnBlur: NotesOptionsProps['closeOnBlur'] @@ -121,15 +121,15 @@ const NoteAttributes: FunctionComponent<{ } const SpellcheckOptions: FunctionComponent<{ - viewControllerManager: ViewControllerManager + editorForNote: SNComponent | undefined + notesController: NotesController note: SNNote -}> = ({ viewControllerManager, note }) => { - const editor = viewControllerManager.application.componentManager.editorForNote(note) - const spellcheckControllable = Boolean(!editor || editor.package_info.spellcheckControl) +}> = ({ editorForNote, notesController, note }) => { + const spellcheckControllable = Boolean(!editorForNote || editorForNote.package_info.spellcheckControl) const noteSpellcheck = !spellcheckControllable ? true : note - ? viewControllerManager.notesController.getSpellcheckStateForNote(note) + ? notesController.getSpellcheckStateForNote(note) : undefined return ( @@ -137,7 +137,7 @@ const SpellcheckOptions: FunctionComponent<{ @@ -427,7 +442,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
- +
diff --git a/app/assets/javascripts/Components/NotesOptions/NotesOptionsPanel.tsx b/app/assets/javascripts/Components/NotesOptions/NotesOptionsPanel.tsx index dfb0d64619a..d90f2fadde6 100644 --- a/app/assets/javascripts/Components/NotesOptions/NotesOptionsPanel.tsx +++ b/app/assets/javascripts/Components/NotesOptions/NotesOptionsPanel.tsx @@ -1,4 +1,3 @@ -import { ViewControllerManager } from '@/Services/ViewControllerManager' import Icon from '@/Components/Icon/Icon' import VisuallyHidden from '@reach/visually-hidden' import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur' @@ -8,14 +7,25 @@ import { observer } from 'mobx-react-lite' import NotesOptions from './NotesOptions' import { WebApplication } from '@/Application/Application' import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants' +import { NotesController } from '@/Controllers/NotesController' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' +import { NoteTagsController } from '@/Controllers/NoteTagsController' type Props = { application: WebApplication - viewControllerManager: ViewControllerManager + navigationController: NavigationController + notesController: NotesController + noteTagsController: NoteTagsController onClickPreprocessing?: () => Promise } -const NotesOptionsPanel = ({ application, viewControllerManager, onClickPreprocessing }: Props) => { +const NotesOptionsPanel = ({ + application, + navigationController, + notesController, + noteTagsController, + onClickPreprocessing, +}: Props) => { const [open, setOpen] = useState(false) const [position, setPosition] = useState({ top: 0, @@ -82,7 +92,9 @@ const NotesOptionsPanel = ({ application, viewControllerManager, onClickPreproce {open && ( )} diff --git a/app/assets/javascripts/Components/NotesOptions/NotesOptionsProps.ts b/app/assets/javascripts/Components/NotesOptions/NotesOptionsProps.ts index 6f10ede6aa7..665eaaf4130 100644 --- a/app/assets/javascripts/Components/NotesOptions/NotesOptionsProps.ts +++ b/app/assets/javascripts/Components/NotesOptions/NotesOptionsProps.ts @@ -1,8 +1,12 @@ import { WebApplication } from '@/Application/Application' -import { ViewControllerManager } from '@/Services/ViewControllerManager' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' +import { NotesController } from '@/Controllers/NotesController' +import { NoteTagsController } from '@/Controllers/NoteTagsController' export type NotesOptionsProps = { application: WebApplication - viewControllerManager: ViewControllerManager + navigationController: NavigationController + notesController: NotesController + noteTagsController: NoteTagsController closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void } diff --git a/app/assets/javascripts/Components/PinNoteButton/PinNoteButton.tsx b/app/assets/javascripts/Components/PinNoteButton/PinNoteButton.tsx index 8ec22bd1e2f..7d25808eff6 100644 --- a/app/assets/javascripts/Components/PinNoteButton/PinNoteButton.tsx +++ b/app/assets/javascripts/Components/PinNoteButton/PinNoteButton.tsx @@ -1,21 +1,17 @@ -import { ViewControllerManager } from '@/Services/ViewControllerManager' import VisuallyHidden from '@reach/visually-hidden' import { observer } from 'mobx-react-lite' import { FunctionComponent, useCallback } from 'react' import Icon from '@/Components/Icon/Icon' +import { NotesController } from '@/Controllers/NotesController' type Props = { - viewControllerManager: ViewControllerManager className?: string + notesController: NotesController onClickPreprocessing?: () => Promise } -const PinNoteButton: FunctionComponent = ({ - viewControllerManager, - className = '', - onClickPreprocessing, -}: Props) => { - const notes = viewControllerManager.notesController.selectedNotes +const PinNoteButton: FunctionComponent = ({ className = '', notesController, onClickPreprocessing }: Props) => { + const notes = notesController.selectedNotes const pinned = notes.some((note) => note.pinned) const togglePinned = useCallback(async () => { @@ -23,11 +19,11 @@ const PinNoteButton: FunctionComponent = ({ await onClickPreprocessing() } if (!pinned) { - viewControllerManager.notesController.setPinSelectedNotes(true) + notesController.setPinSelectedNotes(true) } else { - viewControllerManager.notesController.setPinSelectedNotes(false) + notesController.setPinSelectedNotes(false) } - }, [viewControllerManager, onClickPreprocessing, pinned]) + }, [onClickPreprocessing, pinned, notesController]) return (