Skip to content

Commit

Permalink
feat: file drop handling for super notes (#1990)
Browse files Browse the repository at this point in the history
  • Loading branch information
moughxyz committed Nov 9, 2022
1 parent c961d5e commit fdf9ab0
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import AndroidBackHandlerProvider from '@/NativeMobileWeb/useAndroidBackHandler'
import ConfirmDeleteAccountContainer from '@/Components/ConfirmDeleteAccountModal/ConfirmDeleteAccountModal'
import DarkModeHandler from '../DarkModeHandler/DarkModeHandler'
import ApplicationProvider from './ApplicationProvider'
import { ErrorBoundary } from '@/Utils/ErrorBoundary'

type Props = {
application: WebApplication
Expand Down Expand Up @@ -219,7 +220,9 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
searchOptionsController={viewControllerManager.searchOptionsController}
linkingController={viewControllerManager.linkingController}
/>
<NoteGroupView application={application} />
<ErrorBoundary>
<NoteGroupView application={application} />
</ErrorBoundary>
</FileDragNDropProvider>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import FilePlugin from './Plugins/EncryptedFilePlugin/FilePlugin'
import BlockPickerMenuPlugin from './Plugins/BlockPickerPlugin/BlockPickerPlugin'
import { ErrorBoundary } from '@/Utils/ErrorBoundary'
import { LinkingController } from '@/Controllers/LinkingController'
import LinkingControllerProvider from './Contexts/LinkingControllerProvider'
import LinkingControllerProvider from '../../Controllers/LinkingControllerProvider'
import { BubbleNode } from './Plugins/ItemBubblePlugin/Nodes/BubbleNode'
import ItemBubblePlugin from './Plugins/ItemBubblePlugin/ItemBubblePlugin'
import { NodeObserverPlugin } from './Plugins/NodeObserverPlugin/NodeObserverPlugin'
import { FilesController } from '@/Controllers/FilesController'
import FilesControllerProvider from '@/Controllers/FilesControllerProvider'

const StringEllipses = '...'
const NotePreviewCharLimit = 160
Expand All @@ -21,9 +23,10 @@ type Props = {
application: WebApplication
note: SNNote
linkingController: LinkingController
filesController: FilesController
}

export const BlockEditor: FunctionComponent<Props> = ({ note, application, linkingController }) => {
export const BlockEditor: FunctionComponent<Props> = ({ note, application, linkingController, filesController }) => {
const controller = useRef(new BlockEditorController(note, application))

const handleChange = useCallback(
Expand Down Expand Up @@ -51,19 +54,21 @@ export const BlockEditor: FunctionComponent<Props> = ({ note, application, linki
<div className="relative h-full w-full p-5">
<ErrorBoundary>
<LinkingControllerProvider controller={linkingController}>
<BlocksEditorComposer initialValue={note.text} nodes={[FileNode, BubbleNode]}>
<BlocksEditor
onChange={handleChange}
className="relative relative resize-none text-base focus:shadow-none focus:outline-none"
>
<ItemSelectionPlugin currentNote={note} />
<FilePlugin />
<ItemBubblePlugin />
<BlockPickerMenuPlugin />
<NodeObserverPlugin nodeType={BubbleNode} onRemove={handleBubbleRemove} />
<NodeObserverPlugin nodeType={FileNode} onRemove={handleBubbleRemove} />
</BlocksEditor>
</BlocksEditorComposer>
<FilesControllerProvider controller={filesController}>
<BlocksEditorComposer initialValue={note.text} nodes={[FileNode, BubbleNode]}>
<BlocksEditor
onChange={handleChange}
className="relative relative resize-none text-base focus:shadow-none focus:outline-none"
>
<ItemSelectionPlugin currentNote={note} />
<FilePlugin />
<ItemBubblePlugin />
<BlockPickerMenuPlugin />
<NodeObserverPlugin nodeType={BubbleNode} onRemove={handleBubbleRemove} />
<NodeObserverPlugin nodeType={FileNode} onRemove={handleBubbleRemove} />
</BlocksEditor>
</BlocksEditorComposer>
</FilesControllerProvider>
</LinkingControllerProvider>
</ErrorBoundary>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import { FileNode } from './Nodes/FileNode'
import { $createParagraphNode, $insertNodes, $isRootOrShadowRoot, COMMAND_PRIORITY_EDITOR } from 'lexical'
import { $createFileNode } from './Nodes/FileUtils'
import { $wrapNodeInElement } from '@lexical/utils'
import { useFilesController } from '@/Controllers/FilesControllerProvider'
import { FilesControllerEvent } from '@/Controllers/FilesController'

export default function FilePlugin(): JSX.Element | null {
const [editor] = useLexicalComposerContext()
const filesController = useFilesController()

useEffect(() => {
if (!editor.hasNodes([FileNode])) {
Expand All @@ -19,7 +22,6 @@ export default function FilePlugin(): JSX.Element | null {
INSERT_FILE_COMMAND,
(payload) => {
const fileNode = $createFileNode(payload)
// $insertNodeToNearestRoot(fileNode)
$insertNodes([fileNode])
if ($isRootOrShadowRoot(fileNode.getParentOrThrow())) {
$wrapNodeInElement(fileNode, $createParagraphNode).selectEnd()
Expand All @@ -31,5 +33,16 @@ export default function FilePlugin(): JSX.Element | null {
)
}, [editor])

useEffect(() => {
const disposer = filesController.addEventObserver((event, data) => {
if (event === FilesControllerEvent.FileUploadedToNote) {
const fileUuid = data[FilesControllerEvent.FileUploadedToNote].uuid
editor.dispatchCommand(INSERT_FILE_COMMAND, fileUuid)
}
})

return disposer
}, [filesController, editor])

return null
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react'
import { useApplication } from '@/Components/ApplicationView/ApplicationProvider'
import LinkedItemBubble from '@/Components/LinkedItems/LinkedItemBubble'
import { createLinkFromItem } from '@/Utils/Items/Search/createLinkFromItem'
import { useLinkingController } from '@/Components/BlockEditor/Contexts/LinkingControllerProvider'
import { useLinkingController } from '@/Controllers/LinkingControllerProvider'
import { LinkableItem } from '@/Utils/Items/Search/LinkableItem'
import { useResponsiveAppPane } from '@/Components/ResponsivePane/ResponsivePaneProvider'
import { LexicalNode } from 'lexical'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ContentType, SNNote } from '@standardnotes/snjs'
import { getLinkingSearchResults } from '@/Utils/Items/Search/getSearchResults'
import Popover from '@/Components/Popover/Popover'
import { INSERT_BUBBLE_COMMAND, INSERT_FILE_COMMAND } from '../Commands'
import { useLinkingController } from '../../Contexts/LinkingControllerProvider'
import { useLinkingController } from '../../../../Controllers/LinkingControllerProvider'
import { PopoverClassNames } from '../ClassNames'

type Props = {
Expand Down
4 changes: 2 additions & 2 deletions packages/web/src/javascripts/Components/NoteView/NoteView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import ProtectedItemOverlay from '@/Components/ProtectedItemOverlay/ProtectedIte
import { ElementIds } from '@/Constants/ElementIDs'
import { PrefDefaults } from '@/Constants/PrefDefaults'
import { StringDeleteNote, STRING_DELETE_LOCKED_ATTEMPT, STRING_DELETE_PLACEHOLDER_ATTEMPT } from '@/Constants/Strings'
import { featureTrunkEnabled, FeatureTrunkName } from '@/FeatureTrunk'
import { log, LoggingDomain } from '@/Logging'
import { debounce, isDesktopApplication, isMobileScreen } from '@/Utils'
import { classNames } from '@/Utils/ConcatenateClassNames'
Expand Down Expand Up @@ -996,7 +995,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
const renderHeaderOptions = isMobileScreen() ? !this.state.plaintextEditorFocused : true

const editorMode =
featureTrunkEnabled(FeatureTrunkName.Blocks) && this.note.noteType === NoteType.Blocks
this.note.noteType === NoteType.Blocks
? 'blocks'
: this.state.editorStateDidLoad && !this.state.editorComponentViewer && !this.state.textareaUnloading
? 'plain'
Expand Down Expand Up @@ -1155,6 +1154,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
application={this.application}
note={this.note}
linkingController={this.viewControllerManager.linkingController}
filesController={this.viewControllerManager.filesController}
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { CrossControllerEvent } from '../CrossControllerEvent'
import { InternalEventBus, InternalEventPublishStrategy } from '@standardnotes/snjs'
import { InternalEventBus, InternalEventPublishStrategy, removeFromArray } from '@standardnotes/snjs'
import { WebApplication } from '../../Application/Application'
import { Disposer } from '@/Types/Disposer'

export abstract class AbstractViewController {
type ControllerEventObserver<Event = void, EventData = void> = (event: Event, data: EventData) => void

export abstract class AbstractViewController<Event = void, EventData = void> {
dealloced = false
protected disposers: Disposer[] = []
private eventObservers: ControllerEventObserver<Event, EventData>[] = []

constructor(public application: WebApplication, protected eventBus: InternalEventBus) {}

Expand All @@ -23,5 +26,19 @@ export abstract class AbstractViewController {
}

;(this.disposers as unknown) = undefined

this.eventObservers.length = 0
}

addEventObserver(observer: ControllerEventObserver<Event, EventData>): () => void {
this.eventObservers.push(observer)

return () => {
removeFromArray(this.eventObservers, observer)
}
}

notifyEvent(event: Event, data: EventData): void {
this.eventObservers.forEach((observer) => observer(event, data))
}
}
16 changes: 15 additions & 1 deletion packages/web/src/javascripts/Controllers/FilesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,17 @@ const NonMutatingFileActions = [PopoverFileItemActionType.DownloadFile, PopoverF

type FileContextMenuLocation = { x: number; y: number }

export class FilesController extends AbstractViewController {
export type FilesControllerEventData = {
[FilesControllerEvent.FileUploadedToNote]: {
uuid: string
}
}

export enum FilesControllerEvent {
FileUploadedToNote,
}

export class FilesController extends AbstractViewController<FilesControllerEvent, FilesControllerEventData> {
allFiles: FileItem[] = []
attachedFiles: FileItem[] = []
showFileContextMenu = false
Expand Down Expand Up @@ -388,6 +398,10 @@ export class FilesController extends AbstractViewController {
type: ToastType.Success,
message: `Uploaded file "${uploadedFile.name}"`,
})

this.notifyEvent(FilesControllerEvent.FileUploadedToNote, {
[FilesControllerEvent.FileUploadedToNote]: { uuid: uploadedFile.uuid },
})
}

return uploadedFiles
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ReactNode, createContext, useContext, memo } from 'react'
import { observer } from 'mobx-react-lite'
import { FilesController } from '@/Controllers/FilesController'

const FilesControllerContext = createContext<FilesController | undefined>(undefined)

export const useFilesController = () => {
const value = useContext(FilesControllerContext)

if (!value) {
throw new Error('Component must be a child of <FilesControllerProvider />')
}

return value
}

type ChildrenProps = {
children: ReactNode
}

type ProviderProps = {
controller: FilesController
} & ChildrenProps

const MemoizedChildren = memo(({ children }: ChildrenProps) => <>{children}</>)

const FilesControllerProvider = ({ controller, children }: ProviderProps) => {
return (
<FilesControllerContext.Provider value={controller}>
<MemoizedChildren children={children} />
</FilesControllerContext.Provider>
)
}

export default observer(FilesControllerProvider)
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ReactNode, createContext, useContext, memo } from 'react'

import { observer } from 'mobx-react-lite'
import { LinkingController } from '@/Controllers/LinkingController'

Expand Down

0 comments on commit fdf9ab0

Please sign in to comment.