refactor(web): dependency management (#2386)

This commit is contained in:
Mo
2023-08-05 12:48:39 -05:00
committed by GitHub
parent b07da5b663
commit d8d4052a52
274 changed files with 4065 additions and 3873 deletions

View File

@@ -1,8 +1,7 @@
import { ApplicationEvent } from '@standardnotes/snjs'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { autorun, IReactionDisposer, IReactionPublic } from 'mobx'
import { Component } from 'react'
import { WebApplication } from '@/Application/WebApplication'
export type PureComponentState = Partial<Record<string, unknown>>
export type PureComponentProps = Partial<Record<string, unknown>>
@@ -13,7 +12,7 @@ export abstract class AbstractComponent<P = PureComponentProps, S = PureComponen
constructor(
props: P,
protected application: WebApplication,
public readonly application: WebApplication,
) {
super(props)
}
@@ -40,10 +39,6 @@ export abstract class AbstractComponent<P = PureComponentProps, S = PureComponen
this.deinit()
}
public get viewControllerManager(): ViewControllerManager {
return this.application.controllers
}
autorun(view: (r: IReactionPublic) => void): void {
this.reactionDisposers.push(autorun(view))
}

View File

@@ -1,35 +1,30 @@
import { observer } from 'mobx-react-lite'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { WebApplication } from '@/Application/WebApplication'
import { useCallback, FunctionComponent, KeyboardEventHandler } from 'react'
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { AccountMenuPane } from './AccountMenuPane'
import MenuPaneSelector from './MenuPaneSelector'
import { KeyboardKey } from '@standardnotes/ui-services'
import { useApplication } from '../ApplicationProvider'
export type AccountMenuProps = {
viewControllerManager: ViewControllerManager
application: WebApplication
onClickOutside: () => void
mainApplicationGroup: WebApplicationGroup
}
const AccountMenu: FunctionComponent<AccountMenuProps> = ({
application,
viewControllerManager,
mainApplicationGroup,
}) => {
const { currentPane } = viewControllerManager.accountMenuController
const AccountMenu: FunctionComponent<AccountMenuProps> = ({ mainApplicationGroup }) => {
const application = useApplication()
const { currentPane } = application.accountMenuController
const closeAccountMenu = useCallback(() => {
viewControllerManager.accountMenuController.closeAccountMenu()
}, [viewControllerManager])
application.accountMenuController.closeAccountMenu()
}, [application])
const setCurrentPane = useCallback(
(pane: AccountMenuPane) => {
viewControllerManager.accountMenuController.setCurrentPane(pane)
application.accountMenuController.setCurrentPane(pane)
},
[viewControllerManager],
[application],
)
const handleKeyDown: KeyboardEventHandler<HTMLDivElement> = useCallback(
@@ -50,8 +45,6 @@ const AccountMenu: FunctionComponent<AccountMenuProps> = ({
return (
<div id="account-menu" className="sn-component" onKeyDown={handleKeyDown}>
<MenuPaneSelector
viewControllerManager={viewControllerManager}
application={application}
mainApplicationGroup={mainApplicationGroup}
menuPane={currentPane}
setMenuPane={setCurrentPane}

View File

@@ -1,14 +1,11 @@
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { ChangeEventHandler, FunctionComponent, ReactNode, useCallback, useEffect, useState } from 'react'
import Checkbox from '@/Components/Checkbox/Checkbox'
import DecoratedInput from '@/Components/Input/DecoratedInput'
import Icon from '@/Components/Icon/Icon'
import { useApplication } from '../ApplicationProvider'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
disabled?: boolean
onPrivateUsernameModeChange?: (isPrivate: boolean, identifier?: string) => void
onStrictSignInChange?: (isStrictSignIn: boolean) => void
@@ -17,15 +14,15 @@ type Props = {
}
const AdvancedOptions: FunctionComponent<Props> = ({
viewControllerManager,
application,
disabled = false,
onPrivateUsernameModeChange,
onStrictSignInChange,
onRecoveryCodesChange,
children,
}) => {
const { server, setServer, enableServerOption, setEnableServerOption } = viewControllerManager.accountMenuController
const application = useApplication()
const { server, setServer, enableServerOption, setEnableServerOption } = application.accountMenuController
const [showAdvanced, setShowAdvanced] = useState(false)
const [isPrivateUsername, setIsPrivateUsername] = useState(false)

View File

@@ -1,6 +1,4 @@
import { STRING_NON_MATCHING_PASSWORDS } from '@/Constants/Strings'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import {
FormEventHandler,
@@ -17,23 +15,18 @@ import Checkbox from '@/Components/Checkbox/Checkbox'
import DecoratedPasswordInput from '@/Components/Input/DecoratedPasswordInput'
import Icon from '@/Components/Icon/Icon'
import IconButton from '@/Components/Button/IconButton'
import { useApplication } from '../ApplicationProvider'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
setMenuPane: (pane: AccountMenuPane) => void
email: string
password: string
}
const ConfirmPassword: FunctionComponent<Props> = ({
application,
viewControllerManager,
setMenuPane,
email,
password,
}) => {
const { notesAndTagsCount } = viewControllerManager.accountMenuController
const ConfirmPassword: FunctionComponent<Props> = ({ setMenuPane, email, password }) => {
const application = useApplication()
const { notesAndTagsCount } = application.accountMenuController
const [confirmPassword, setConfirmPassword] = useState('')
const [isRegistering, setIsRegistering] = useState(false)
const [isEphemeral, setIsEphemeral] = useState(false)
@@ -72,8 +65,8 @@ const ConfirmPassword: FunctionComponent<Props> = ({
application
.register(email, password, isEphemeral, shouldMergeLocal)
.then(() => {
viewControllerManager.accountMenuController.closeAccountMenu()
viewControllerManager.accountMenuController.setCurrentPane(AccountMenuPane.GeneralMenu)
application.accountMenuController.closeAccountMenu()
application.accountMenuController.setCurrentPane(AccountMenuPane.GeneralMenu)
})
.catch((err) => {
console.error(err)
@@ -88,7 +81,7 @@ const ConfirmPassword: FunctionComponent<Props> = ({
passwordInputRef.current?.focus()
}
},
[viewControllerManager, application, confirmPassword, email, isEphemeral, password, shouldMergeLocal],
[application, confirmPassword, email, isEphemeral, password, shouldMergeLocal],
)
const handleKeyDown: KeyboardEventHandler = useCallback(

View File

@@ -1,5 +1,3 @@
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import {
FormEventHandler,
@@ -20,8 +18,6 @@ import AdvancedOptions from './AdvancedOptions'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
setMenuPane: (pane: AccountMenuPane) => void
email: string
setEmail: React.Dispatch<React.SetStateAction<string>>
@@ -29,15 +25,7 @@ type Props = {
setPassword: React.Dispatch<React.SetStateAction<string>>
}
const CreateAccount: FunctionComponent<Props> = ({
viewControllerManager,
application,
setMenuPane,
email,
setEmail,
password,
setPassword,
}) => {
const CreateAccount: FunctionComponent<Props> = ({ setMenuPane, email, setEmail, password, setPassword }) => {
const emailInputRef = useRef<HTMLInputElement>(null)
const passwordInputRef = useRef<HTMLInputElement>(null)
const [isPrivateUsername, setIsPrivateUsername] = useState(false)
@@ -145,11 +133,7 @@ const CreateAccount: FunctionComponent<Props> = ({
<Button className="mt-1" label="Next" primary onClick={handleRegisterFormSubmit} fullWidth={true} />
</form>
<HorizontalSeparator classes="my-2" />
<AdvancedOptions
application={application}
viewControllerManager={viewControllerManager}
onPrivateUsernameModeChange={onPrivateUsernameChange}
/>
<AdvancedOptions onPrivateUsernameModeChange={onPrivateUsernameChange} />
</>
)
}

View File

@@ -1,5 +1,3 @@
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import Icon from '@/Components/Icon/Icon'
import { SyncQueueStrategy } from '@standardnotes/snjs'
@@ -14,10 +12,9 @@ import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { formatLastSyncDate } from '@/Utils/DateUtils'
import Spinner from '@/Components/Spinner/Spinner'
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
import { useApplication } from '../ApplicationProvider'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
mainApplicationGroup: WebApplicationGroup
setMenuPane: (pane: AccountMenuPane) => void
closeMenu: () => void
@@ -25,13 +22,9 @@ type Props = {
const iconClassName = `text-neutral mr-2 ${MenuItemIconSize}`
const GeneralAccountMenu: FunctionComponent<Props> = ({
application,
viewControllerManager,
setMenuPane,
closeMenu,
mainApplicationGroup,
}) => {
const GeneralAccountMenu: FunctionComponent<Props> = ({ setMenuPane, closeMenu, mainApplicationGroup }) => {
const application = useApplication()
const [isSyncingInProgress, setIsSyncingInProgress] = useState(false)
const [lastSyncDate, setLastSyncDate] = useState(formatLastSyncDate(application.sync.getLastSyncDate() as Date))
@@ -58,23 +51,23 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
})
}, [application])
const user = useMemo(() => application.getUser(), [application])
const user = useMemo(() => application.sessions.getUser(), [application])
const openPreferences = useCallback(() => {
viewControllerManager.accountMenuController.closeAccountMenu()
viewControllerManager.preferencesController.setCurrentPane('account')
viewControllerManager.preferencesController.openPreferences()
}, [viewControllerManager])
application.accountMenuController.closeAccountMenu()
application.preferencesController.setCurrentPane('account')
application.preferencesController.openPreferences()
}, [application])
const openHelp = useCallback(() => {
viewControllerManager.accountMenuController.closeAccountMenu()
viewControllerManager.preferencesController.setCurrentPane('help-feedback')
viewControllerManager.preferencesController.openPreferences()
}, [viewControllerManager])
application.accountMenuController.closeAccountMenu()
application.preferencesController.setCurrentPane('help-feedback')
application.preferencesController.openPreferences()
}, [application])
const signOut = useCallback(() => {
viewControllerManager.accountMenuController.setSigningOut(true)
}, [viewControllerManager])
application.accountMenuController.setSigningOut(true)
}, [application])
const activateRegisterPane = useCallback(() => {
setMenuPane(AccountMenuPane.Register)
@@ -100,7 +93,7 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
<div className="mb-3 px-3 text-lg text-foreground lg:text-sm">
<div>You're signed in as:</div>
<div className="wrap my-0.5 font-bold">{user.email}</div>
<span className="text-neutral">{application.getHost()}</span>
<span className="text-neutral">{application.getHost.execute().getValue()}</span>
</div>
<div className="mb-2 flex items-start justify-between px-3 text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item">
{isSyncingInProgress ? (
@@ -137,16 +130,13 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
</>
)}
<Menu
isOpen={viewControllerManager.accountMenuController.show}
isOpen={application.accountMenuController.show}
a11yLabel="General account menu"
closeMenu={closeMenu}
initialFocus={!application.hasAccount() ? CREATE_ACCOUNT_INDEX : SWITCHER_INDEX}
>
<MenuItemSeparator />
<WorkspaceSwitcherOption
mainApplicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager}
/>
<WorkspaceSwitcherOption mainApplicationGroup={mainApplicationGroup} />
<MenuItemSeparator />
{user ? (
<MenuItem onClick={openPreferences}>
@@ -167,8 +157,8 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
)}
<MenuItem
onClick={() => {
viewControllerManager.importModalController.setIsVisible(true)
viewControllerManager.accountMenuController.closeAccountMenu()
application.importModalController.setIsVisible(true)
application.accountMenuController.closeAccountMenu()
}}
>
<Icon type="archive" className={iconClassName} />

View File

@@ -1,6 +1,4 @@
import { WebApplication } from '@/Application/WebApplication'
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useState } from 'react'
import { AccountMenuPane } from './AccountMenuPane'
@@ -10,22 +8,13 @@ import GeneralAccountMenu from './GeneralAccountMenu'
import SignInPane from './SignIn'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
mainApplicationGroup: WebApplicationGroup
menuPane: AccountMenuPane
setMenuPane: (pane: AccountMenuPane) => void
closeMenu: () => void
}
const MenuPaneSelector: FunctionComponent<Props> = ({
application,
viewControllerManager,
menuPane,
setMenuPane,
closeMenu,
mainApplicationGroup,
}) => {
const MenuPaneSelector: FunctionComponent<Props> = ({ menuPane, setMenuPane, closeMenu, mainApplicationGroup }) => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
@@ -33,22 +22,16 @@ const MenuPaneSelector: FunctionComponent<Props> = ({
case AccountMenuPane.GeneralMenu:
return (
<GeneralAccountMenu
viewControllerManager={viewControllerManager}
application={application}
mainApplicationGroup={mainApplicationGroup}
setMenuPane={setMenuPane}
closeMenu={closeMenu}
/>
)
case AccountMenuPane.SignIn:
return (
<SignInPane viewControllerManager={viewControllerManager} application={application} setMenuPane={setMenuPane} />
)
return <SignInPane setMenuPane={setMenuPane} />
case AccountMenuPane.Register:
return (
<CreateAccount
viewControllerManager={viewControllerManager}
application={application}
setMenuPane={setMenuPane}
email={email}
setEmail={setEmail}
@@ -57,15 +40,7 @@ const MenuPaneSelector: FunctionComponent<Props> = ({
/>
)
case AccountMenuPane.ConfirmPassword:
return (
<ConfirmPassword
viewControllerManager={viewControllerManager}
application={application}
setMenuPane={setMenuPane}
email={email}
password={password}
/>
)
return <ConfirmPassword setMenuPane={setMenuPane} email={email} password={password} />
}
}

View File

@@ -1,5 +1,3 @@
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { isDev } from '@/Utils'
import { observer } from 'mobx-react-lite'
import React, { FunctionComponent, KeyboardEventHandler, useCallback, useEffect, useRef, useState } from 'react'
@@ -13,15 +11,16 @@ import IconButton from '@/Components/Button/IconButton'
import AdvancedOptions from './AdvancedOptions'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
import { getErrorFromErrorResponse, isErrorResponse } from '@standardnotes/snjs'
import { useApplication } from '../ApplicationProvider'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
setMenuPane: (pane: AccountMenuPane) => void
}
const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManager, setMenuPane }) => {
const { notesAndTagsCount } = viewControllerManager.accountMenuController
const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
const application = useApplication()
const { notesAndTagsCount } = application.accountMenuController
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [recoveryCodes, setRecoveryCodes] = useState('')
@@ -101,7 +100,7 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
if (isErrorResponse(response)) {
throw new Error(getErrorFromErrorResponse(response).message)
}
viewControllerManager.accountMenuController.closeAccountMenu()
application.accountMenuController.closeAccountMenu()
})
.catch((err) => {
console.error(err)
@@ -112,7 +111,7 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
.finally(() => {
setIsSigningIn(false)
})
}, [viewControllerManager, application, email, isEphemeral, isStrictSignin, password, shouldMergeLocal])
}, [application, email, isEphemeral, isStrictSignin, password, shouldMergeLocal])
const recoverySignIn = useCallback(() => {
setIsSigningIn(true)
@@ -129,7 +128,7 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
if (result.isFailed()) {
throw new Error(result.getError())
}
viewControllerManager.accountMenuController.closeAccountMenu()
application.accountMenuController.closeAccountMenu()
})
.catch((err) => {
console.error(err)
@@ -140,7 +139,7 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
.finally(() => {
setIsSigningIn(false)
})
}, [viewControllerManager, application, email, password, recoveryCodes])
}, [application, email, password, recoveryCodes])
const onPrivateUsernameChange = useCallback(
(newisPrivateUsername: boolean, privateUsernameIdentifier?: string) => {
@@ -251,8 +250,6 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
</div>
<HorizontalSeparator classes="my-2" />
<AdvancedOptions
viewControllerManager={viewControllerManager}
application={application}
disabled={isSigningIn}
onPrivateUsernameModeChange={onPrivateUsernameChange}
onStrictSignInChange={handleStrictSigninChange}

View File

@@ -1,25 +1,20 @@
import { observer } from 'mobx-react-lite'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { WebApplication } from '@/Application/WebApplication'
import { User as UserType } from '@standardnotes/snjs'
import { useApplication } from '../ApplicationProvider'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
}
const User = () => {
const application = useApplication()
const User = ({ viewControllerManager, application }: Props) => {
const { server } = viewControllerManager.accountMenuController
const user = application.getUser() as UserType
const { server } = application.accountMenuController
const user = application.sessions.getUser() as UserType
return (
<div className="sk-panel-section">
{viewControllerManager.syncStatusController.errorMessage && (
{application.syncStatusController.errorMessage && (
<div className="sk-notification danger">
<div className="sk-notification-title">Sync Unreachable</div>
<div className="sk-notification-text">
Hmm...we can't seem to sync your account. The reason:{' '}
{viewControllerManager.syncStatusController.errorMessage}
Hmm...we can't seem to sync your account. The reason: {application.syncStatusController.errorMessage}
</div>
<a
className="sk-a info-contrast sk-bold sk-panel-row"

View File

@@ -1,5 +1,4 @@
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { ApplicationDescriptor, ApplicationGroupEvent, ButtonType } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
@@ -8,20 +7,21 @@ import Menu from '@/Components/Menu/Menu'
import MenuItem from '@/Components/Menu/MenuItem'
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
import WorkspaceMenuItem from './WorkspaceMenuItem'
import { useApplication } from '@/Components/ApplicationProvider'
type Props = {
mainApplicationGroup: WebApplicationGroup
viewControllerManager: ViewControllerManager
isOpen: boolean
hideWorkspaceOptions?: boolean
}
const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
mainApplicationGroup,
viewControllerManager,
isOpen,
hideWorkspaceOptions = false,
}: Props) => {
const application = useApplication()
const [applicationDescriptors, setApplicationDescriptors] = useState<ApplicationDescriptor[]>(
mainApplicationGroup.getDescriptors(),
)
@@ -43,7 +43,7 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
}, [mainApplicationGroup])
const signoutAll = useCallback(async () => {
const confirmed = await viewControllerManager.application.alerts.confirm(
const confirmed = await application.alerts.confirm(
'Are you sure you want to sign out of all workspaces on this device?',
undefined,
'Sign out all',
@@ -53,11 +53,11 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
return
}
mainApplicationGroup.signOutAllWorkspaces().catch(console.error)
}, [mainApplicationGroup, viewControllerManager])
}, [mainApplicationGroup, application])
const destroyWorkspace = useCallback(() => {
viewControllerManager.accountMenuController.setSigningOut(true)
}, [viewControllerManager])
application.accountMenuController.setSigningOut(true)
}, [application])
const activateWorkspace = useCallback(
async (descriptor: ApplicationDescriptor) => {

View File

@@ -1,6 +1,5 @@
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants'
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useRef, useState } from 'react'
import Icon from '@/Components/Icon/Icon'
@@ -11,10 +10,9 @@ import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
type Props = {
mainApplicationGroup: WebApplicationGroup
viewControllerManager: ViewControllerManager
}
const WorkspaceSwitcherOption: FunctionComponent<Props> = ({ mainApplicationGroup, viewControllerManager }) => {
const WorkspaceSwitcherOption: FunctionComponent<Props> = ({ mainApplicationGroup }) => {
const buttonRef = useRef<HTMLButtonElement>(null)
const [isOpen, setIsOpen] = useState(false)
@@ -40,11 +38,7 @@ const WorkspaceSwitcherOption: FunctionComponent<Props> = ({ mainApplicationGrou
side="right"
togglePopover={toggleMenu}
>
<WorkspaceSwitcherMenu
mainApplicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager}
isOpen={isOpen}
/>
<WorkspaceSwitcherMenu mainApplicationGroup={mainApplicationGroup} isOpen={isOpen} />
</Popover>
</>
)

View File

@@ -1,7 +1,7 @@
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { getPlatformString, isIOS } from '@/Utils'
import { getPlatformString } from '@/Utils'
import { ApplicationEvent, Challenge, removeFromArray, WebAppEvent } from '@standardnotes/snjs'
import { alertDialog, RouteType } from '@standardnotes/ui-services'
import { alertDialog, isIOS, RouteType } from '@standardnotes/ui-services'
import { WebApplication } from '@/Application/WebApplication'
import Footer from '@/Components/Footer/Footer'
import SessionsModal from '@/Components/SessionsModal/SessionsModal'
@@ -30,6 +30,7 @@ import LinkingControllerProvider from '@/Controllers/LinkingControllerProvider'
import ImportModal from '../ImportModal/ImportModal'
import IosKeyboardClose from '../IosKeyboardClose/IosKeyboardClose'
import EditorWidthSelectionModalWrapper from '../EditorWidthSelectionModal/EditorWidthSelectionModal'
import { ProtectionEvent } from '@standardnotes/services'
type Props = {
application: WebApplication
@@ -47,10 +48,8 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
const currentWriteErrorDialog = useRef<Promise<void> | null>(null)
const currentLoadErrorDialog = useRef<Promise<void> | null>(null)
const viewControllerManager = application.controllers
useEffect(() => {
const desktopService = application.getDesktopService()
const desktopService = application.desktopManager
if (desktopService) {
application.componentManager.setDesktopManager(desktopService)
@@ -142,10 +141,6 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
})
.catch(console.error)
}
} else if (eventName === ApplicationEvent.BiometricsSoftLockEngaged) {
setNeedsUnlock(true)
} else if (eventName === ApplicationEvent.BiometricsSoftLockDisengaged) {
setNeedsUnlock(false)
}
})
@@ -154,10 +149,22 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
}
}, [application, onAppLaunch, onAppStart])
useEffect(() => {
const disposer = application.protections.addEventObserver(async (eventName) => {
if (eventName === ProtectionEvent.BiometricsSoftLockEngaged) {
setNeedsUnlock(true)
} else if (eventName === ProtectionEvent.BiometricsSoftLockDisengaged) {
setNeedsUnlock(false)
}
})
return disposer
}, [application])
useEffect(() => {
const removeObserver = application.addWebEventObserver(async (eventName) => {
if (eventName === WebAppEvent.WindowDidFocus) {
if (!(await application.isLocked())) {
if (!(await application.protections.isLocked())) {
application.sync.sync().catch(console.error)
}
}
@@ -178,14 +185,13 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
<ChallengeModal
key={`${challenge.id}${application.ephemeralIdentifier}`}
application={application}
viewControllerManager={viewControllerManager}
mainApplicationGroup={mainApplicationGroup}
challenge={challenge}
onDismiss={removeChallenge}
/>
</div>
))
}, [viewControllerManager, challenges, mainApplicationGroup, removeChallenge, application])
}, [challenges, mainApplicationGroup, removeChallenge, application])
if (!renderAppContents) {
return <AndroidBackHandlerProvider application={application}>{renderChallenges()}</AndroidBackHandlerProvider>
@@ -198,23 +204,13 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
<ApplicationProvider application={application}>
<CommandProvider service={application.keyboardService}>
<AndroidBackHandlerProvider application={application}>
<ResponsivePaneProvider paneController={application.controllers.paneController}>
<PremiumModalProvider
application={application}
featuresController={viewControllerManager.featuresController}
>
<LinkingControllerProvider controller={viewControllerManager.linkingController}>
<FileDragNDropProvider
application={application}
featuresController={viewControllerManager.featuresController}
filesController={viewControllerManager.filesController}
>
<LazyLoadedClipperView
viewControllerManager={viewControllerManager}
applicationGroup={mainApplicationGroup}
/>
<ResponsivePaneProvider paneController={application.paneController}>
<PremiumModalProvider application={application}>
<LinkingControllerProvider controller={application.linkingController}>
<FileDragNDropProvider application={application}>
<LazyLoadedClipperView applicationGroup={mainApplicationGroup} />
<ToastContainer />
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
<FilePreviewModalWrapper application={application} />
{renderChallenges()}
</FileDragNDropProvider>
</LinkingControllerProvider>
@@ -230,64 +226,38 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
<ApplicationProvider application={application}>
<CommandProvider service={application.keyboardService}>
<AndroidBackHandlerProvider application={application}>
<ResponsivePaneProvider paneController={application.controllers.paneController}>
<PremiumModalProvider
application={application}
featuresController={viewControllerManager.featuresController}
>
<LinkingControllerProvider controller={viewControllerManager.linkingController}>
<ResponsivePaneProvider paneController={application.paneController}>
<PremiumModalProvider application={application}>
<LinkingControllerProvider controller={application.linkingController}>
<div className={platformString + ' main-ui-view sn-component h-full'}>
<FileDragNDropProvider
application={application}
featuresController={viewControllerManager.featuresController}
filesController={viewControllerManager.filesController}
>
<FileDragNDropProvider application={application}>
<PanesSystemComponent />
</FileDragNDropProvider>
<>
<Footer application={application} applicationGroup={mainApplicationGroup} />
<SessionsModal application={application} viewControllerManager={viewControllerManager} />
<PreferencesViewWrapper viewControllerManager={viewControllerManager} application={application} />
<RevisionHistoryModal
application={application}
historyModalController={viewControllerManager.historyModalController}
selectionController={viewControllerManager.selectionController}
/>
<SessionsModal application={application} />
<PreferencesViewWrapper application={application} />
<RevisionHistoryModal application={application} />
</>
{renderChallenges()}
<>
<NotesContextMenu
navigationController={viewControllerManager.navigationController}
notesController={viewControllerManager.notesController}
linkingController={viewControllerManager.linkingController}
historyModalController={viewControllerManager.historyModalController}
selectionController={viewControllerManager.selectionController}
/>
<NotesContextMenu />
<TagContextMenuWrapper
navigationController={viewControllerManager.navigationController}
featuresController={viewControllerManager.featuresController}
navigationController={application.navigationController}
featuresController={application.featuresController}
/>
<FileContextMenuWrapper
filesController={viewControllerManager.filesController}
selectionController={viewControllerManager.selectionController}
navigationController={viewControllerManager.navigationController}
linkingController={viewControllerManager.linkingController}
/>
<PurchaseFlowWrapper application={application} viewControllerManager={viewControllerManager} />
<ConfirmSignoutContainer
applicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager}
application={application}
filesController={application.filesController}
itemListController={application.itemListController}
/>
<PurchaseFlowWrapper application={application} />
<ConfirmSignoutContainer applicationGroup={mainApplicationGroup} application={application} />
<ToastContainer />
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
<FilePreviewModalWrapper application={application} />
<PermissionsModalWrapper application={application} />
<EditorWidthSelectionModalWrapper />
<ConfirmDeleteAccountContainer
application={application}
viewControllerManager={viewControllerManager}
/>
<ImportModal importModalController={viewControllerManager.importModalController} />
<ConfirmDeleteAccountContainer application={application} />
<ImportModal importModalController={application.importModalController} />
</>
{application.routeService.isDotOrg && <DotOrgNotice />}
{isIOS() && <IosKeyboardClose />}

View File

@@ -22,7 +22,7 @@ const BiometricsPrompt = ({ application, onValueChange, prompt, buttonRef }: Pro
fullWidth
colorStyle={authenticated ? 'success' : 'info'}
onClick={async () => {
const authenticated = await application.mobileDevice().authenticateWithBiometrics()
const authenticated = await application.mobileDevice.authenticateWithBiometrics()
setAuthenticated(authenticated)
onValueChange(authenticated, prompt)
}}

View File

@@ -15,7 +15,6 @@ import Icon from '@/Components/Icon/Icon'
import ChallengeModalPrompt from './ChallengePrompt'
import LockscreenWorkspaceSwitcher from './LockscreenWorkspaceSwitcher'
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { ChallengeModalValues } from './ChallengeModalValues'
import { InputValue } from './InputValue'
import { classNames } from '@standardnotes/utils'
@@ -26,7 +25,6 @@ import { useAutoElementRect } from '@/Hooks/useElementRect'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
mainApplicationGroup: WebApplicationGroup
challenge: Challenge
onDismiss?: (challenge: Challenge) => void
@@ -48,13 +46,7 @@ const validateValues = (values: ChallengeModalValues, prompts: ChallengePrompt[]
return undefined
}
const ChallengeModal: FunctionComponent<Props> = ({
application,
viewControllerManager,
mainApplicationGroup,
challenge,
onDismiss,
}) => {
const ChallengeModal: FunctionComponent<Props> = ({ application, mainApplicationGroup, challenge, onDismiss }) => {
const promptsContainerRef = useRef<HTMLFormElement>(null)
const [values, setValues] = useState<ChallengeModalValues>(() => {
@@ -341,12 +333,7 @@ const ChallengeModal: FunctionComponent<Props> = ({
Forgot passcode?
</Button>
)}
{shouldShowWorkspaceSwitcher && (
<LockscreenWorkspaceSwitcher
mainApplicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager}
/>
)}
{shouldShowWorkspaceSwitcher && <LockscreenWorkspaceSwitcher mainApplicationGroup={mainApplicationGroup} />}
</div>
</Modal>
</ModalOverlay>

View File

@@ -39,7 +39,7 @@ const ChallengeModalPrompt: FunctionComponent<Props> = ({
const activatePrompt = useCallback(async () => {
if (prompt.validation === ChallengeValidation.Biometric) {
if (application.isNativeMobileWeb()) {
const appState = await application.mobileDevice().getAppState()
const appState = await application.mobileDevice.getAppState()
if (appState !== 'active') {
return

View File

@@ -1,5 +1,4 @@
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { FunctionComponent, useCallback, useRef, useState } from 'react'
import WorkspaceSwitcherMenu from '@/Components/AccountMenu/WorkspaceSwitcher/WorkspaceSwitcherMenu'
import Button from '@/Components/Button/Button'
@@ -8,10 +7,9 @@ import Popover from '../Popover/Popover'
type Props = {
mainApplicationGroup: WebApplicationGroup
viewControllerManager: ViewControllerManager
}
const LockscreenWorkspaceSwitcher: FunctionComponent<Props> = ({ mainApplicationGroup, viewControllerManager }) => {
const LockscreenWorkspaceSwitcher: FunctionComponent<Props> = ({ mainApplicationGroup }) => {
const buttonRef = useRef<HTMLButtonElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
const [isOpen, setIsOpen] = useState(false)
@@ -38,7 +36,6 @@ const LockscreenWorkspaceSwitcher: FunctionComponent<Props> = ({ mainApplication
>
<WorkspaceSwitcherMenu
mainApplicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager}
isOpen={isOpen}
hideWorkspaceOptions={true}
/>

View File

@@ -3,13 +3,13 @@ import { ChallengePrompt } from '@standardnotes/services'
import { RefObject, useState } from 'react'
import { WebApplication } from '@/Application/WebApplication'
import { isAndroid } from '@/Utils'
import Button from '../Button/Button'
import Icon from '../Icon/Icon'
import { InputValue } from './InputValue'
import U2FPromptIframeContainer from './U2FPromptIframeContainer'
import { isAndroid } from '@standardnotes/ui-services'
type Props = {
application: WebApplication
@@ -27,7 +27,7 @@ const U2FPrompt = ({ application, onValueChange, prompt, buttonRef, contextData
return (
<U2FPromptIframeContainer
contextData={contextData}
apiHost={application.getHost() || window.defaultSyncServer}
apiHost={application.getHost.execute().getValue() || window.defaultSyncServer}
onResponse={(response) => {
onValueChange(response, prompt)
}}
@@ -60,9 +60,9 @@ const U2FPrompt = ({ application, onValueChange, prompt, buttonRef, contextData
}
const authenticatorOptions = authenticatorOptionsOrError.getValue()
authenticatorResponse = await application
.mobileDevice()
.authenticateWithU2F(JSON.stringify(authenticatorOptions))
authenticatorResponse = await application.mobileDevice.authenticateWithU2F(
JSON.stringify(authenticatorOptions),
)
} else {
const authenticatorResponseOrError = await application.getAuthenticatorAuthenticationResponse.execute({
username: username.value,

View File

@@ -1,4 +1,3 @@
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import ChangeEditorMenu from './ChangeEditorMenu'
@@ -11,19 +10,14 @@ import { NoteViewController } from '../NoteView/Controller/NoteViewController'
import { NoteType, noteTypeForEditorIdentifier } from '@standardnotes/snjs'
type Props = {
viewControllerManager: ViewControllerManager
noteViewController?: NoteViewController
onClickPreprocessing?: () => Promise<void>
}
const ChangeEditorButton: FunctionComponent<Props> = ({
viewControllerManager,
noteViewController,
onClickPreprocessing,
}: Props) => {
const ChangeEditorButton: FunctionComponent<Props> = ({ noteViewController, onClickPreprocessing }: Props) => {
const application = useApplication()
const note = viewControllerManager.notesController.firstSelectedNote
const note = application.notesController.firstSelectedNote
const [isOpen, setIsOpen] = useState(false)
const buttonRef = useRef<HTMLButtonElement>(null)
const containerRef = useRef<HTMLDivElement>(null)

View File

@@ -85,14 +85,14 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
const selectComponent = useCallback(
async (uiFeature: UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>, note: SNNote) => {
if (uiFeature.isComponent && uiFeature.asComponent.conflictOf) {
void application.changeAndSaveItem(uiFeature.asComponent, (mutator) => {
void application.changeAndSaveItem.execute(uiFeature.asComponent, (mutator) => {
mutator.conflictOf = undefined
})
}
await application.controllers.itemListController.insertCurrentIfTemplate()
await application.itemListController.insertCurrentIfTemplate()
await application.changeAndSaveItem(note, (mutator) => {
await application.changeAndSaveItem.execute(note, (mutator) => {
const noteMutator = mutator as NoteMutator
noteMutator.noteType = uiFeature.noteType
noteMutator.editorIdentifier = uiFeature.featureIdentifier

View File

@@ -42,12 +42,12 @@ const ChangeEditorMultipleMenu = ({ application, notes, setDisableClickOutside }
const selectComponent = useCallback(
async (uiFeature: UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>, note: SNNote) => {
if (uiFeature.isComponent && uiFeature.asComponent.conflictOf) {
void application.changeAndSaveItem(uiFeature.asComponent, (mutator) => {
void application.changeAndSaveItem.execute(uiFeature.asComponent, (mutator) => {
mutator.conflictOf = undefined
})
}
await application.changeAndSaveItem(note, (mutator) => {
await application.changeAndSaveItem.execute(note, (mutator) => {
const noteMutator = mutator as NoteMutator
noteMutator.noteType = uiFeature.noteType
noteMutator.editorIdentifier = uiFeature.featureIdentifier

View File

@@ -24,7 +24,17 @@ const ClippedNoteView = ({
}) => {
const application = useApplication()
const syncController = useRef(new NoteSyncController(application, note))
const syncController = useRef(
new NoteSyncController(
note,
application.items,
application.mutator,
application.sessions,
application.sync,
application.alerts,
application.isNativeMobileWebUseCase,
),
)
useEffect(() => {
const currentController = syncController.current
return () => {

View File

@@ -1,5 +1,4 @@
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { useCallback, useEffect, useState } from 'react'
import { AccountMenuPane } from '../AccountMenu/AccountMenuPane'
import MenuPaneSelector from '../AccountMenu/MenuPaneSelector'
@@ -29,7 +28,7 @@ import { getSuperJSONFromClipPayload } from './getSuperJSONFromClipHTML'
import ClippedNoteView from './ClippedNoteView'
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
import Button from '../Button/Button'
import { openSubscriptionDashboard } from '@/Utils/ManageSubscription'
import { useStateRef } from '@/Hooks/useStateRef'
import usePreference from '@/Hooks/usePreference'
import { createLinkFromItem } from '@/Utils/Items/Search/createLinkFromItem'
@@ -39,13 +38,7 @@ import StyledTooltip from '../StyledTooltip/StyledTooltip'
import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem'
import Spinner from '../Spinner/Spinner'
const ClipperView = ({
viewControllerManager,
applicationGroup,
}: {
viewControllerManager: ViewControllerManager
applicationGroup: WebApplicationGroup
}) => {
const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGroup }) => {
const application = useApplication()
const [currentWindow, setCurrentWindow] = useState<Awaited<ReturnType<typeof windows.getCurrent>>>()
@@ -61,7 +54,7 @@ const ClipperView = ({
}, [])
const isFirefoxPopup = !!currentWindow && currentWindow.type === 'popup' && currentWindow.incognito === false
const [user, setUser] = useState(() => application.getUser())
const [user, setUser] = useState(() => application.sessions.getUser())
const [isSyncing, setIsSyncing] = useState(false)
const [hasSyncError, setHasSyncError] = useState(false)
useEffect(() => {
@@ -81,7 +74,7 @@ const ClipperView = ({
case ApplicationEvent.SignedIn:
case ApplicationEvent.SignedOut:
case ApplicationEvent.UserRolesChanged:
setUser(application.getUser())
setUser(application.sessions.getUser())
setIsEntitled(
application.features.getFeatureStatus(
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.Clipper).getValue(),
@@ -223,7 +216,7 @@ const ClipperView = ({
type: 'image/png',
})
const uploadedFile = await viewControllerManager.filesController.uploadNewFile(file).catch(console.error)
const uploadedFile = await application.filesController.uploadNewFile(file).catch(console.error)
if (uploadedFile && defaultTagRef.current) {
await application.linkingController.linkItems(uploadedFile, defaultTagRef.current)
@@ -269,6 +262,7 @@ const ClipperView = ({
createNoteFromClip().catch(console.error)
}, [
application.filesController,
application.items,
application.linkingController,
application.mutator,
@@ -276,12 +270,11 @@ const ClipperView = ({
clipPayload,
defaultTagRef,
isEntitledRef,
viewControllerManager.filesController,
])
const upgradePlan = useCallback(async () => {
if (hasSubscription) {
await openSubscriptionDashboard(application)
await application.openSubscriptionDashboard.execute()
} else {
await application.openPurchaseFlow()
}
@@ -317,7 +310,7 @@ const ClipperView = ({
<ClippedNoteView
note={clippedNote}
key={clippedNote.uuid}
linkingController={viewControllerManager.linkingController}
linkingController={application.linkingController}
clearClip={clearClip}
isFirefoxPopup={isFirefoxPopup}
/>
@@ -328,8 +321,6 @@ const ClipperView = ({
return menuPane ? (
<div className="py-1">
<MenuPaneSelector
viewControllerManager={viewControllerManager}
application={application}
mainApplicationGroup={applicationGroup}
menuPane={menuPane}
setMenuPane={setMenuPane}

View File

@@ -153,7 +153,7 @@ const IframeFeatureView: FunctionComponent<Props> = ({ onLoad, componentViewer,
application.keyboardService.handleComponentKeyUp(data.keyboardModifier)
break
case ComponentAction.Click:
application.controllers.notesController.setContextMenuOpen(false)
application.notesController.setContextMenuOpen(false)
break
default:
return
@@ -165,13 +165,13 @@ const IframeFeatureView: FunctionComponent<Props> = ({ onLoad, componentViewer,
}, [componentViewer, application])
useEffect(() => {
const unregisterDesktopObserver = application
.getDesktopService()
?.registerUpdateObserver((updatedComponent: ComponentInterface) => {
const unregisterDesktopObserver = application.desktopManager?.registerUpdateObserver(
(updatedComponent: ComponentInterface) => {
if (updatedComponent.uuid === uiFeature.uniqueIdentifier.value) {
requestReload?.(componentViewer)
}
})
},
)
return () => {
unregisterDesktopObserver?.()

View File

@@ -3,7 +3,6 @@ import { FunctionComponent, useCallback } from 'react'
import Button from '@/Components/Button/Button'
import { WarningCircle } from '../UIElements/WarningCircle'
import { useApplication } from '../ApplicationProvider'
import { openSubscriptionDashboard } from '@/Utils/ManageSubscription'
type Props = {
feature: AnyFeatureDescription
@@ -33,7 +32,7 @@ const NotEntitledBanner: FunctionComponent<Props> = ({ featureStatus, feature })
const expiredDate = application.subscriptions.userSubscriptionExpirationDate
const manageSubscription = useCallback(() => {
void openSubscriptionDashboard(application)
void application.openSubscriptionDashboard.execute()
}, [application])
return (

View File

@@ -1,5 +1,4 @@
import { observer } from 'mobx-react-lite'
import { ViewControllerManager } from '@Controllers/ViewControllerManager'
import { useCallback, useRef } from 'react'
import { STRING_DELETE_ACCOUNT_CONFIRMATION } from '@/Constants/Strings'
import Button from '@/Components/Button/Button'
@@ -8,14 +7,13 @@ import Icon from '../Icon/Icon'
import AlertDialog from '../AlertDialog/AlertDialog'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
}
const ConfirmDeleteAccountModal = ({ application, viewControllerManager }: Props) => {
const ConfirmDeleteAccountModal = ({ application }: Props) => {
const closeDialog = useCallback(() => {
viewControllerManager.accountMenuController.setDeletingAccount(false)
}, [viewControllerManager.accountMenuController])
application.accountMenuController.setDeletingAccount(false)
}, [application.accountMenuController])
const cancelRef = useRef<HTMLButtonElement>(null)
@@ -52,7 +50,7 @@ const ConfirmDeleteAccountModal = ({ application, viewControllerManager }: Props
ConfirmDeleteAccountModal.displayName = 'ConfirmDeleteAccountModal'
const ConfirmDeleteAccountContainer = (props: Props) => {
if (!props.viewControllerManager.accountMenuController.deletingAccount) {
if (!props.application.accountMenuController.deletingAccount) {
return null
}
return <ConfirmDeleteAccountModal {...props} />

View File

@@ -1,7 +1,6 @@
import { FunctionComponent, useCallback, useRef } from 'react'
import { STRING_SIGN_OUT_CONFIRMATION } from '@/Constants/Strings'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
import { isDesktopApplication } from '@/Utils'
@@ -12,11 +11,10 @@ import HorizontalSeparator from '../Shared/HorizontalSeparator'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
applicationGroup: WebApplicationGroup
}
const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewControllerManager, applicationGroup }) => {
const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, applicationGroup }) => {
const hasAnyBackupsEnabled =
application.fileBackups?.isFilesBackupsEnabled() ||
application.fileBackups?.isPlaintextBackupsEnabled() ||
@@ -24,8 +22,8 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
const cancelRef = useRef<HTMLButtonElement>(null)
const closeDialog = useCallback(() => {
viewControllerManager.accountMenuController.setSigningOut(false)
}, [viewControllerManager.accountMenuController])
application.accountMenuController.setSigningOut(false)
}, [application.accountMenuController])
const workspaces = applicationGroup.getDescriptors()
const showWorkspaceWarning = workspaces.length > 1 && isDesktopApplication()
@@ -98,7 +96,7 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
ConfirmSignoutModal.displayName = 'ConfirmSignoutModal'
const ConfirmSignoutContainer = (props: Props) => {
if (!props.viewControllerManager.accountMenuController.signingOut) {
if (!props.application.accountMenuController.signingOut) {
return null
}
return <ConfirmSignoutModal {...props} />

View File

@@ -5,39 +5,22 @@ import { FunctionComponent, KeyboardEventHandler, UIEventHandler, useCallback }
import { FOCUSABLE_BUT_NOT_TABBABLE, NOTES_LIST_SCROLL_THRESHOLD } from '@/Constants/Constants'
import { ListableContentItem } from './Types/ListableContentItem'
import ContentListItem from './ContentListItem'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
import { FilesController } from '@/Controllers/FilesController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { ElementIds } from '@/Constants/ElementIDs'
import { classNames } from '@standardnotes/utils'
import { ContentType, SNTag } from '@standardnotes/snjs'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
type Props = {
application: WebApplication
filesController: FilesController
itemListController: ItemListController
items: ListableContentItem[]
navigationController: NavigationController
notesController: NotesController
selectionController: SelectedItemsController
selectedUuids: SelectedItemsController['selectedUuids']
selectedUuids: ItemListController['selectedUuids']
paginate: () => void
}
const ContentList: FunctionComponent<Props> = ({
application,
filesController,
itemListController,
items,
navigationController,
notesController,
selectionController,
selectedUuids,
paginate,
}) => {
const { selectPreviousItem, selectNextItem } = selectionController
const ContentList: FunctionComponent<Props> = ({ application, items, selectedUuids, paginate }) => {
const { filesController, itemListController, navigationController, notesController } = application
const { selectPreviousItem, selectNextItem } = itemListController
const { hideTags, hideDate, hideNotePreview, hideEditorIcon } = itemListController.webDisplayOptions
const { sortBy } = itemListController.displayOptions
const selectedTag = navigationController.selected
@@ -68,9 +51,9 @@ const ContentList: FunctionComponent<Props> = ({
const selectItem = useCallback(
(item: ListableContentItem, userTriggered?: boolean) => {
return selectionController.selectItem(item.uuid, userTriggered)
return itemListController.selectItem(item.uuid, userTriggered)
},
[selectionController],
[itemListController],
)
const getTagsForItem = useCallback(

View File

@@ -14,22 +14,13 @@ import { observer } from 'mobx-react-lite'
import { forwardRef, useCallback, useEffect, useMemo } from 'react'
import ContentList from '@/Components/ContentListView/ContentList'
import NoAccountWarning from '@/Components/NoAccountWarning/NoAccountWarning'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { FilesController } from '@/Controllers/FilesController'
import { NoAccountWarningController } from '@/Controllers/NoAccountWarningController'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { AccountMenuController } from '@/Controllers/AccountMenu/AccountMenuController'
import { ElementIds } from '@/Constants/ElementIDs'
import ContentListHeader from './Header/ContentListHeader'
import { AppPaneId } from '../Panes/AppPaneMetadata'
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
import SearchBar from '../SearchBar/SearchBar'
import { SearchOptionsController } from '@/Controllers/SearchOptionsController'
import { classNames } from '@standardnotes/utils'
import { useFileDragNDrop } from '../FileDragNDropProvider'
import { LinkingController } from '@/Controllers/LinkingController'
import DailyContentList from './Daily/DailyContentList'
import { ListableContentItem } from './Types/ListableContentItem'
import { FeatureName } from '@/Controllers/FeatureName'
@@ -37,29 +28,14 @@ import { PanelResizedData } from '@/Types/PanelResizedData'
import { useForwardedRef } from '@/Hooks/useForwardedRef'
import FloatingAddButton from './FloatingAddButton'
import ContentTableView from '../ContentTableView/ContentTableView'
import { FeaturesController } from '@/Controllers/FeaturesController'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
import { PaneController } from '@/Controllers/PaneController/PaneController'
import EmptyFilesView from './EmptyFilesView'
import { PaneLayout } from '@/Controllers/PaneController/PaneLayout'
import { usePaneSwipeGesture } from '../Panes/usePaneGesture'
import { mergeRefs } from '@/Hooks/mergeRefs'
type Props = {
accountMenuController: AccountMenuController
application: WebApplication
filesController: FilesController
itemListController: ItemListController
navigationController: NavigationController
noAccountWarningController: NoAccountWarningController
notesController: NotesController
selectionController: SelectedItemsController
searchOptionsController: SearchOptionsController
linkingController: LinkingController
featuresController: FeaturesController
historyModalController: HistoryModalController
paneController: PaneController
className?: string
id: string
children?: React.ReactNode
@@ -67,30 +43,20 @@ type Props = {
}
const ContentListView = forwardRef<HTMLDivElement, Props>(
(
{
({ application, className, id, children, onPanelWidthLoad }, ref) => {
const {
paneController,
accountMenuController,
application,
filesController,
itemListController,
navigationController,
noAccountWarningController,
notesController,
selectionController,
searchOptionsController,
linkingController,
featuresController,
historyModalController,
paneController,
className,
id,
children,
onPanelWidthLoad,
},
ref,
) => {
} = application
const { setPaneLayout, panes } = useResponsiveAppPane()
const { selectedUuids, selectNextItem, selectPreviousItem } = selectionController
const { selected: selectedTag, selectedAsTag } = navigationController
const {
completedFullSync,
@@ -102,6 +68,9 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
items,
isCurrentNoteTemplate,
isTableViewEnabled,
selectedUuids,
selectNextItem,
selectPreviousItem,
} = itemListController
const innerRef = useForwardedRef(ref)
@@ -260,7 +229,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
}
event.preventDefault()
selectionController.selectAll()
itemListController.selectAll()
},
},
])
@@ -268,9 +237,9 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
addNewItem,
application.keyboardService,
createNewNote,
itemListController,
selectNextItem,
selectPreviousItem,
selectionController,
shouldUseTableView,
])
@@ -289,13 +258,13 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
const handleDailyListSelection = useCallback(
async (item: ListableContentItem, userTriggered: boolean) => {
await selectionController.selectItemWithScrollHandling(item, {
await itemListController.selectItemWithScrollHandling(item, {
userTriggered: true,
scrollIntoView: userTriggered === false,
animated: false,
})
},
[selectionController],
[itemListController],
)
useEffect(() => {
@@ -371,29 +340,13 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
) : null}
{!dailyMode && renderedItems.length ? (
shouldUseTableView ? (
<ContentTableView
items={items}
application={application}
filesController={filesController}
featuresController={featuresController}
linkingController={linkingController}
navigationController={navigationController}
notesController={notesController}
historyModalController={historyModalController}
itemListController={itemListController}
selectionController={selectionController}
/>
<ContentTableView items={items} application={application} />
) : (
<ContentList
items={renderedItems}
selectedUuids={selectedUuids}
application={application}
paginate={paginate}
filesController={filesController}
itemListController={itemListController}
navigationController={navigationController}
notesController={notesController}
selectionController={selectionController}
/>
)
) : null}

View File

@@ -1,7 +1,6 @@
import { FunctionComponent, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
import { ListableContentItem } from '../Types/ListableContentItem'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import { useResponsiveAppPane } from '../../Panes/ResponsivePaneProvider'
import { AppPaneId } from '../../Panes/AppPaneMetadata'
import {
@@ -25,7 +24,7 @@ type Props = {
items: ListableContentItem[]
onSelect: (item: ListableContentItem, userTriggered: boolean) => Promise<void>
selectedTag: SNTag
selectedUuids: SelectedItemsController['selectedUuids']
selectedUuids: ItemListController['selectedUuids']
}
const PageSize = 10

View File

@@ -93,7 +93,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
: selectedTag.preferences
const [currentMode, setCurrentMode] = useState<PreferenceMode>(selectedTagPreferences ? 'tag' : 'global')
const [preferences, setPreferences] = useState<TagPreferences>({})
const hasSubscription = application.controllers.subscriptionController.hasFirstPartyOnlineOrOfflineSubscription
const hasSubscription = application.subscriptionController.hasFirstPartyOnlineOrOfflineSubscription
const controlsDisabled = currentMode === 'tag' && !hasSubscription
const isDailyEntry = selectedTagPreferences?.entryMode === 'daily'
@@ -181,7 +181,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
} else if (isSystemTag) {
await changeSystemViewPreferences(properties)
} else {
await application.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => {
await application.changeAndSaveItem.execute<TagMutator>(selectedTag, (mutator) => {
mutator.preferences = {
...mutator.preferences,
...properties,
@@ -202,7 +202,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
return
}
void application.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => {
void application.changeAndSaveItem.execute<TagMutator>(selectedTag, (mutator) => {
mutator.preferences = undefined
})
}, [application, isSystemTag, reloadPreferences, selectedTag])

View File

@@ -231,7 +231,7 @@ const NewNotePreferences: FunctionComponent<Props> = ({
onClick={(event) => {
if (application.isNativeMobileWeb()) {
event.preventDefault()
application.mobileDevice().openUrl(HelpPageUrl)
application.mobileDevice.openUrl(HelpPageUrl)
}
}}
>

View File

@@ -1,5 +1,4 @@
import { WebApplication } from '@/Application/WebApplication'
import { FilesController } from '@/Controllers/FilesController'
import { formatDateForContextMenu } from '@/Utils/DateUtils'
import { getIconForFileType } from '@/Utils/Items/Icons/getIconForFileType'
import { formatSizeToReadableString } from '@standardnotes/filepicker'
@@ -28,38 +27,15 @@ import FileMenuOptions from '../FileContextMenu/FileMenuOptions'
import Icon from '../Icon/Icon'
import LinkedItemBubble from '../LinkedItems/LinkedItemBubble'
import LinkedItemsPanel from '../LinkedItems/LinkedItemsPanel'
import { LinkingController } from '@/Controllers/LinkingController'
import { FeaturesController } from '@/Controllers/FeaturesController'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import { useApplication } from '../ApplicationProvider'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { getIconAndTintForNoteType } from '@/Utils/Items/Icons/getIconAndTintForNoteType'
import NotesOptions from '../NotesOptions/NotesOptions'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
import { useItemLinks } from '@/Hooks/useItemLinks'
import { ItemLink } from '@/Utils/Items/Search/ItemLink'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
import ListItemVaultInfo from '../ContentListView/ListItemVaultInfo'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
const ContextMenuCell = ({
items,
filesController,
navigationController,
linkingController,
notesController,
historyModalController,
selectionController,
}: {
items: DecryptedItemInterface[]
filesController: FilesController
navigationController: NavigationController
linkingController: LinkingController
notesController: NotesController
historyModalController: HistoryModalController
selectionController: SelectedItemsController
}) => {
const ContextMenuCell = ({ items }: { items: DecryptedItemInterface[] }) => {
const [contextMenuVisible, setContextMenuVisible] = useState(false)
const anchorElementRef = useRef<HTMLButtonElement>(null)
@@ -102,12 +78,9 @@ const ContextMenuCell = ({
<Menu a11yLabel="File context menu" isOpen={contextMenuVisible}>
{allItemsAreFiles && (
<FileMenuOptions
linkingController={linkingController}
navigationController={navigationController}
closeMenu={() => {
setContextMenuVisible(false)
}}
filesController={filesController}
shouldShowRenameOption={false}
shouldShowAttachOption={false}
selectedFiles={items as FileItem[]}
@@ -116,11 +89,6 @@ const ContextMenuCell = ({
{allItemsAreNotes && (
<NotesOptions
notes={items as SNNote[]}
navigationController={navigationController}
notesController={notesController}
linkingController={linkingController}
historyModalController={historyModalController}
selectionController={selectionController}
closeMenu={() => {
setContextMenuVisible(false)
}}
@@ -132,17 +100,7 @@ const ContextMenuCell = ({
)
}
const ItemLinksCell = ({
item,
filesController,
linkingController,
featuresController,
}: {
item: DecryptedItemInterface
filesController: FilesController
linkingController: LinkingController
featuresController: FeaturesController
}) => {
const ItemLinksCell = ({ item }: { item: DecryptedItemInterface }) => {
const [contextMenuVisible, setContextMenuVisible] = useState(false)
const anchorElementRef = useRef<HTMLButtonElement>(null)
@@ -170,13 +128,7 @@ const ItemLinksCell = ({
align="start"
className="py-2"
>
<LinkedItemsPanel
linkingController={linkingController}
filesController={filesController}
featuresController={featuresController}
isOpen={contextMenuVisible}
item={item}
/>
<LinkedItemsPanel isOpen={contextMenuVisible} item={item} />
</Popover>
</>
)
@@ -263,37 +215,18 @@ const AttachedToCell = ({ item }: { item: DecryptedItemInterface }) => {
type Props = {
application: WebApplication
items: DecryptedItemInterface[]
filesController: FilesController
featuresController: FeaturesController
linkingController: LinkingController
navigationController: NavigationController
notesController: NotesController
historyModalController: HistoryModalController
itemListController: ItemListController
selectionController: SelectedItemsController
}
const ContentTableView = ({
application,
items,
filesController,
featuresController,
linkingController,
navigationController,
notesController,
historyModalController,
itemListController,
selectionController,
}: Props) => {
const ContentTableView = ({ application, items }: Props) => {
const listHasFiles = items.some((item) => item instanceof FileItem)
const { sortBy, sortDirection } = itemListController.displayOptions
const { sortBy, sortDirection } = application.itemListController.displayOptions
const sortReversed = sortDirection === 'asc'
const { hideDate, hideEditorIcon: hideIcon, hideTags } = itemListController.webDisplayOptions
const { hideDate, hideEditorIcon: hideIcon, hideTags } = application.itemListController.webDisplayOptions
const onSortChange = useCallback(
async (sortBy: keyof SortableItem, sortReversed: boolean) => {
const selectedTag = navigationController.selected
const selectedTag = application.navigationController.selected
if (!selectedTag) {
return
@@ -320,7 +253,7 @@ const ContentTableView = ({
return
}
await application.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => {
await application.changeAndSaveItem.execute<TagMutator>(selectedTag, (mutator) => {
mutator.preferences = {
...mutator.preferences,
sortBy,
@@ -328,7 +261,7 @@ const ContentTableView = ({
}
})
},
[application, navigationController.selected],
[application],
)
const [contextMenuItem, setContextMenuItem] = useState<DecryptedItemInterface | undefined>(undefined)
@@ -383,7 +316,7 @@ const ContentTableView = ({
enableMultipleRowSelection: true,
onRowActivate(item) {
if (item instanceof FileItem) {
void filesController.handleFileAction({
void application.filesController.handleFileAction({
type: FileItemActionType.PreviewFile,
payload: {
file: item,
@@ -399,35 +332,12 @@ const ContentTableView = ({
rowActions: (item) => {
return (
<div className="flex items-center gap-2">
<ItemLinksCell
item={item}
filesController={filesController}
featuresController={featuresController}
linkingController={linkingController}
/>
<ContextMenuCell
items={[item]}
filesController={filesController}
linkingController={linkingController}
navigationController={navigationController}
notesController={notesController}
historyModalController={historyModalController}
selectionController={selectionController}
/>
<ItemLinksCell item={item} />
<ContextMenuCell items={[item]} />
</div>
)
},
selectionActions: (itemIds) => (
<ContextMenuCell
items={items.filter((item) => itemIds.includes(item.uuid))}
filesController={filesController}
linkingController={linkingController}
navigationController={navigationController}
notesController={notesController}
historyModalController={historyModalController}
selectionController={selectionController}
/>
),
selectionActions: (itemIds) => <ContextMenuCell items={items.filter((item) => itemIds.includes(item.uuid))} />,
showSelectionActions: true,
})
@@ -456,26 +366,15 @@ const ContentTableView = ({
<Menu a11yLabel="File context menu" isOpen={true}>
<FileMenuOptions
closeMenu={closeContextMenu}
filesController={filesController}
shouldShowRenameOption={false}
shouldShowAttachOption={false}
selectedFiles={[contextMenuItem]}
linkingController={linkingController}
navigationController={navigationController}
/>
</Menu>
)}
{contextMenuItem instanceof SNNote && (
<Menu className="select-none" a11yLabel="Note context menu" isOpen={true}>
<NotesOptions
notes={[contextMenuItem]}
navigationController={navigationController}
notesController={notesController}
linkingController={linkingController}
historyModalController={historyModalController}
selectionController={selectionController}
closeMenu={closeContextMenu}
/>
<NotesOptions notes={[contextMenuItem]} closeMenu={closeContextMenu} />
</Menu>
)}
</Popover>

View File

@@ -154,7 +154,7 @@ const EditorWidthSelectionModal = ({
const EditorWidthSelectionModalWrapper = () => {
const application = useApplication()
const { notesController } = application.controllers
const { notesController } = application
const [isOpen, setIsOpen] = useState(false)
const [isGlobal, setIsGlobal] = useState(false)

View File

@@ -1,60 +1,46 @@
import { FilesController } from '@/Controllers/FilesController'
import { LinkingController } from '@/Controllers/LinkingController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'react'
import Menu from '../Menu/Menu'
import Popover from '../Popover/Popover'
import FileMenuOptions from './FileMenuOptions'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
type Props = {
filesController: FilesController
selectionController: SelectedItemsController
linkingController: LinkingController
navigationController: NavigationController
itemListController: ItemListController
}
const FileContextMenu: FunctionComponent<Props> = observer(
({ filesController, selectionController, linkingController, navigationController }) => {
const { showFileContextMenu, setShowFileContextMenu, fileContextMenuLocation } = filesController
const { selectedFiles } = selectionController
const FileContextMenu: FunctionComponent<Props> = observer(({ filesController, itemListController }) => {
const { showFileContextMenu, setShowFileContextMenu, fileContextMenuLocation } = filesController
const { selectedFiles } = itemListController
return (
<Popover
title="File options"
open={showFileContextMenu}
anchorPoint={fileContextMenuLocation}
togglePopover={() => setShowFileContextMenu(!showFileContextMenu)}
align="start"
className="py-2"
>
<Menu a11yLabel="File context menu" isOpen={showFileContextMenu}>
<FileMenuOptions
filesController={filesController}
linkingController={linkingController}
navigationController={navigationController}
selectedFiles={selectedFiles}
closeMenu={() => setShowFileContextMenu(false)}
shouldShowRenameOption={false}
shouldShowAttachOption={false}
/>
</Menu>
</Popover>
)
},
)
return (
<Popover
title="File options"
open={showFileContextMenu}
anchorPoint={fileContextMenuLocation}
togglePopover={() => setShowFileContextMenu(!showFileContextMenu)}
align="start"
className="py-2"
>
<Menu a11yLabel="File context menu" isOpen={showFileContextMenu}>
<FileMenuOptions
selectedFiles={selectedFiles}
closeMenu={() => setShowFileContextMenu(false)}
shouldShowRenameOption={false}
shouldShowAttachOption={false}
/>
</Menu>
</Popover>
)
})
FileContextMenu.displayName = 'FileContextMenu'
const FileContextMenuWrapper: FunctionComponent<Props> = ({
filesController,
linkingController,
navigationController,
selectionController,
}) => {
const FileContextMenuWrapper: FunctionComponent<Props> = ({ filesController, itemListController }) => {
const { showFileContextMenu } = filesController
const { selectedFiles } = selectionController
const { selectedFiles } = itemListController
const selectedFile = selectedFiles[0]
@@ -62,14 +48,7 @@ const FileContextMenuWrapper: FunctionComponent<Props> = ({
return null
}
return (
<FileContextMenu
filesController={filesController}
linkingController={linkingController}
navigationController={navigationController}
selectionController={selectionController}
/>
)
return <FileContextMenu filesController={filesController} itemListController={itemListController} />
}
export default observer(FileContextMenuWrapper)

View File

@@ -2,7 +2,6 @@ import { FunctionComponent, useCallback, useMemo } from 'react'
import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction'
import Icon from '@/Components/Icon/Icon'
import { observer } from 'mobx-react-lite'
import { FilesController } from '@/Controllers/FilesController'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
import { formatSizeToReadableString } from '@standardnotes/filepicker'
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
@@ -13,17 +12,13 @@ import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem'
import { FileItem } from '@standardnotes/snjs'
import AddTagOption from '../NotesOptions/AddTagOption'
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
import { LinkingController } from '@/Controllers/LinkingController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import AddToVaultMenuOption from '../Vaults/AddToVaultMenuOption'
import { iconClass } from '../NotesOptions/ClassNames'
import { featureTrunkVaultsEnabled } from '@/FeatureTrunk'
import { useApplication } from '../ApplicationProvider'
type Props = {
closeMenu: () => void
filesController: FilesController
linkingController: LinkingController
navigationController: NavigationController
isFileAttachedToNote?: boolean
renameToggleCallback?: (isRenamingFile: boolean) => void
shouldShowRenameOption: boolean
@@ -33,16 +28,15 @@ type Props = {
const FileMenuOptions: FunctionComponent<Props> = ({
closeMenu,
filesController,
linkingController,
navigationController,
isFileAttachedToNote,
renameToggleCallback,
shouldShowRenameOption,
shouldShowAttachOption,
selectedFiles,
}) => {
const { handleFileAction } = filesController
const application = useApplication()
const { handleFileAction } = application.filesController
const { toggleAppPane } = useResponsiveAppPane()
const hasProtectedFiles = useMemo(() => selectedFiles.some((file) => file.protected), [selectedFiles])
@@ -95,15 +89,15 @@ const FileMenuOptions: FunctionComponent<Props> = ({
)}
{featureTrunkVaultsEnabled() && <AddToVaultMenuOption iconClassName={iconClass} items={selectedFiles} />}
<AddTagOption
navigationController={navigationController}
linkingController={linkingController}
navigationController={application.navigationController}
linkingController={application.linkingController}
selectedItems={selectedFiles}
iconClassName={`text-neutral mr-2 ${MenuItemIconSize}`}
/>
<MenuSwitchButtonItem
checked={hasProtectedFiles}
onChange={(hasProtectedFiles) => {
void filesController.setProtectionForFiles(hasProtectedFiles, selectedFiles)
void application.filesController.setProtectionForFiles(hasProtectedFiles, selectedFiles)
}}
>
<Icon type="lock" className={`mr-2 text-neutral ${MenuItemIconSize}`} />
@@ -112,7 +106,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
<HorizontalSeparator classes="my-1" />
<MenuItem
onClick={() => {
void filesController.downloadFiles(selectedFiles)
void application.filesController.downloadFiles(selectedFiles)
closeMenu()
}}
>
@@ -132,7 +126,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
<MenuItem
onClick={() => {
closeMenuAndToggleFilesList()
void filesController.deleteFilesPermanently(selectedFiles)
void application.filesController.deleteFilesPermanently(selectedFiles)
}}
>
<Icon type="trash" className={`mr-2 text-danger ${MenuItemIconSize}`} />

View File

@@ -1,27 +1,16 @@
import { useCallback, useRef, useState } from 'react'
import { observer } from 'mobx-react-lite'
import FileMenuOptions from './FileMenuOptions'
import { FilesController } from '@/Controllers/FilesController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import Popover from '../Popover/Popover'
import RoundIconButton from '../Button/RoundIconButton'
import Menu from '../Menu/Menu'
import { LinkingController } from '@/Controllers/LinkingController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
type Props = {
filesController: FilesController
selectionController: SelectedItemsController
linkingController: LinkingController
navigationController: NavigationController
itemListController: ItemListController
}
const FilesOptionsPanel = ({
filesController,
linkingController,
navigationController,
selectionController,
}: Props) => {
const FilesOptionsPanel = ({ itemListController }: Props) => {
const [isOpen, setIsOpen] = useState(false)
const buttonRef = useRef<HTMLButtonElement>(null)
@@ -39,10 +28,7 @@ const FilesOptionsPanel = ({
>
<Menu a11yLabel="File options panel" isOpen={isOpen}>
<FileMenuOptions
filesController={filesController}
linkingController={linkingController}
navigationController={navigationController}
selectedFiles={selectionController.selectedFiles}
selectedFiles={itemListController.selectedFiles}
closeMenu={() => {
setIsOpen(false)
}}

View File

@@ -1,6 +1,4 @@
import { WebApplication } from '@/Application/WebApplication'
import { FeaturesController } from '@/Controllers/FeaturesController'
import { FilesController } from '@/Controllers/FilesController'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { classNames } from '@standardnotes/utils'
import { isHandlingFileDrag } from '@/Utils/DragTypeCheck'
@@ -35,8 +33,6 @@ export const useFileDragNDrop = () => {
type Props = {
application: WebApplication
featuresController: FeaturesController
filesController: FilesController
children: ReactNode
}
@@ -47,7 +43,7 @@ const MemoizedChildren = memo(({ children }: { children: ReactNode }) => {
return <>{children}</>
})
const FileDragNDropProvider = ({ application, children, featuresController, filesController }: Props) => {
const FileDragNDropProvider = ({ application, children }: Props) => {
const premiumModal = usePremiumModal()
const [isDraggingFiles, setIsDraggingFiles] = useState(false)
const [tooltipText, setTooltipText] = useState('')
@@ -189,7 +185,7 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
resetState()
if (!featuresController.entitledToFiles) {
if (!application.featuresController.entitledToFiles) {
premiumModal.activate('Files')
return
}
@@ -204,7 +200,7 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
return
}
const uploadedFile = await filesController.uploadNewFile(fileOrHandle)
const uploadedFile = await application.filesController.uploadNewFile(fileOrHandle)
if (!uploadedFile) {
return
@@ -218,7 +214,7 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
dragCounter.current = 0
}
},
[application, featuresController.entitledToFiles, filesController, premiumModal, resetState],
[application, premiumModal, resetState],
)
useEffect(() => {

View File

@@ -141,7 +141,7 @@ const FilePreview = ({ file, application, isEmbeddedInSuper = false, imageZoomLe
) : (
<FilePreviewError
file={file}
filesController={application.controllers.filesController}
filesController={application.filesController}
tryAgainCallback={() => {
setDownloadedBytes(undefined)
}}

View File

@@ -5,7 +5,6 @@ import Icon from '@/Components/Icon/Icon'
import FilePreviewInfoPanel from './FilePreviewInfoPanel'
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants'
import { KeyboardKey } from '@standardnotes/ui-services'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import FilePreview from './FilePreview'
import { getIconForFileType } from '@/Utils/Items/Icons/getIconForFileType'
@@ -23,11 +22,10 @@ import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/u
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const FilePreviewModal = observer(({ application, viewControllerManager }: Props) => {
const { currentFile, setCurrentFile, otherFiles, dismiss } = viewControllerManager.filePreviewModalController
const FilePreviewModal = observer(({ application }: Props) => {
const { currentFile, setCurrentFile, otherFiles, dismiss } = application.filePreviewModalController
const [isRenaming, setIsRenaming] = useState(false)
const renameInputRef = useRef<HTMLInputElement>(null)
@@ -229,9 +227,6 @@ const FilePreviewModal = observer(({ application, viewControllerManager }: Props
>
<Menu a11yLabel="File context menu" isOpen={showOptionsMenu}>
<FileMenuOptions
filesController={viewControllerManager.filesController}
linkingController={viewControllerManager.linkingController}
navigationController={viewControllerManager.navigationController}
selectedFiles={[currentFile]}
closeMenu={closeOptionsMenu}
shouldShowRenameOption={false}
@@ -260,10 +255,7 @@ const FilePreviewModal = observer(({ application, viewControllerManager }: Props
</div>
{showLinkedBubblesContainer && (
<div className="-mt-1 min-h-0 flex-shrink-0 border-b border-border px-3.5 py-1.5">
<LinkedItemBubblesContainer
linkingController={viewControllerManager.linkingController}
item={currentFile}
/>
<LinkedItemBubblesContainer linkingController={application.linkingController} item={currentFile} />
</div>
)}
<div className="flex min-h-0 flex-grow flex-col-reverse md:flex-row">
@@ -284,14 +276,14 @@ const FilePreviewModal = observer(({ application, viewControllerManager }: Props
FilePreviewModal.displayName = 'FilePreviewModal'
const FilePreviewModalWrapper: FunctionComponent<Props> = ({ application, viewControllerManager }) => {
const FilePreviewModalWrapper: FunctionComponent<Props> = ({ application }) => {
return (
<ModalOverlay
aria-label="File preview modal"
isOpen={viewControllerManager.filePreviewModalController.isOpen}
close={viewControllerManager.filePreviewModalController.dismiss}
isOpen={application.filePreviewModalController.isOpen}
close={application.filePreviewModalController.dismiss}
>
<FilePreviewModal application={application} viewControllerManager={viewControllerManager} />
<FilePreviewModal application={application} />
</ModalOverlay>
)
}

View File

@@ -61,7 +61,7 @@ const PreviewComponent: FunctionComponent<Props> = ({
const sanitizedName = sanitizeFileName(name)
const filename = `${sanitizedName}.${ext}`
void application.mobileDevice().previewFile(fileBase64, filename)
void application.mobileDevice.previewFile(fileBase64, filename)
}, [application, bytes, file.mimeType, file.name, isNativeMobileWeb])
if (isNativeMobileWeb && requiresNativePreview) {

View File

@@ -5,16 +5,16 @@ import FileViewWithoutProtection from './FileViewWithoutProtection'
import { FileViewProps } from './FileViewProps'
import { ApplicationEvent } from '@standardnotes/snjs'
const FileView = ({ application, viewControllerManager, file }: FileViewProps) => {
const FileView = ({ application, file }: FileViewProps) => {
const [shouldShowProtectedOverlay, setShouldShowProtectedOverlay] = useState(false)
useEffect(() => {
viewControllerManager.filesController.setShowProtectedOverlay(!application.isAuthorizedToRenderItem(file))
}, [application, file, viewControllerManager.filesController])
application.filesController.setShowProtectedOverlay(!application.isAuthorizedToRenderItem(file))
}, [application, file, application.filesController])
useEffect(() => {
setShouldShowProtectedOverlay(viewControllerManager.filesController.showProtectedOverlay)
}, [viewControllerManager.filesController.showProtectedOverlay])
setShouldShowProtectedOverlay(application.filesController.showProtectedOverlay)
}, [application.filesController.showProtectedOverlay])
const dismissProtectedOverlay = useCallback(async () => {
let showFileContents = true
@@ -48,7 +48,7 @@ const FileView = ({ application, viewControllerManager, file }: FileViewProps) =
itemType={'file'}
/>
) : (
<FileViewWithoutProtection application={application} viewControllerManager={viewControllerManager} file={file} />
<FileViewWithoutProtection application={application} file={file} />
)
}

View File

@@ -1,9 +1,7 @@
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { FileItem } from '@standardnotes/snjs'
export type FileViewProps = {
application: WebApplication
viewControllerManager: ViewControllerManager
file: FileItem
}

View File

@@ -15,7 +15,7 @@ import RoundIconButton from '../Button/RoundIconButton'
const SyncTimeoutNoDebounceMs = 100
const SyncTimeoutDebounceMs = 350
const FileViewWithoutProtection = ({ application, viewControllerManager, file }: FileViewProps) => {
const FileViewWithoutProtection = ({ application, file }: FileViewProps) => {
const syncTimeoutRef = useRef<number>()
const fileInfoButtonRef = useRef<HTMLButtonElement>(null)
@@ -30,7 +30,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
clearTimeout(syncTimeoutRef.current)
}
const shouldNotDebounce = application.noAccount()
const shouldNotDebounce = application.sessions.isSignedOut()
const syncDebounceMs = shouldNotDebounce ? SyncTimeoutNoDebounceMs : SyncTimeoutDebounceMs
syncTimeoutRef.current = window.setTimeout(async () => {
@@ -52,7 +52,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
addDragTarget(target, {
tooltipText: 'Drop your files to upload and link them to the current file',
async callback(uploadedFile) {
await viewControllerManager.linkingController.linkItems(uploadedFile, file)
await application.linkingController.linkItems(uploadedFile, file)
},
})
}
@@ -62,7 +62,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
removeDragTarget(target)
}
}
}, [addDragTarget, file, removeDragTarget, viewControllerManager.linkingController])
}, [addDragTarget, file, removeDragTarget, application.linkingController])
return (
<div className="sn-component section editor" aria-label="File" ref={fileDragTargetRef}>
@@ -89,11 +89,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
</div>
</div>
<div className="flex items-center gap-3">
<LinkedItemsButton
filesController={viewControllerManager.filesController}
linkingController={viewControllerManager.linkingController}
featuresController={viewControllerManager.featuresController}
/>
<LinkedItemsButton linkingController={application.linkingController} />
<RoundIconButton
label="File information panel"
onClick={toggleFileInfoPanel}
@@ -110,16 +106,11 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
>
<FilePreviewInfoPanel file={file} />
</Popover>
<FileOptionsPanel
filesController={viewControllerManager.filesController}
selectionController={viewControllerManager.selectionController}
linkingController={viewControllerManager.linkingController}
navigationController={viewControllerManager.navigationController}
/>
<FileOptionsPanel itemListController={application.itemListController} />
</div>
</div>
<div className="hidden md:flex">
<LinkedItemBubblesContainer item={file} linkingController={viewControllerManager.linkingController} />
<LinkedItemBubblesContainer item={file} linkingController={application.linkingController} />
</div>
</div>
</div>

View File

@@ -12,16 +12,7 @@ type Props = AccountMenuProps & {
user: unknown
}
const AccountMenuButton = ({
application,
hasError,
isOpen,
mainApplicationGroup,
onClickOutside,
toggleMenu,
user,
viewControllerManager,
}: Props) => {
const AccountMenuButton = ({ hasError, isOpen, mainApplicationGroup, onClickOutside, toggleMenu, user }: Props) => {
const buttonRef = useRef<HTMLButtonElement>(null)
return (
@@ -49,12 +40,7 @@ const AccountMenuButton = ({
align="start"
className="py-2"
>
<AccountMenu
onClickOutside={onClickOutside}
viewControllerManager={viewControllerManager}
application={application}
mainApplicationGroup={mainApplicationGroup}
/>
<AccountMenu onClickOutside={onClickOutside} mainApplicationGroup={mainApplicationGroup} />
</Popover>
</>
)

View File

@@ -125,12 +125,10 @@ class Footer extends AbstractComponent<Props, State> {
})
this.autorun(() => {
const showBetaWarning = this.viewControllerManager.showBetaWarning
this.setState({
showBetaWarning: showBetaWarning,
showAccountMenu: this.viewControllerManager.accountMenuController.show,
showQuickSettingsMenu: this.viewControllerManager.quickSettingsMenuController.open,
showVaultSelectionMenu: this.viewControllerManager.vaultSelectionController.open,
showAccountMenu: this.application.accountMenuController.show,
showQuickSettingsMenu: this.application.quickSettingsMenuController.open,
showVaultSelectionMenu: this.application.vaultSelectionController.open,
})
})
}
@@ -156,7 +154,7 @@ class Footer extends AbstractComponent<Props, State> {
}
reloadUser() {
this.user = this.application.getUser()
this.user = this.application.sessions.getUser()
}
async reloadPasscodeStatus() {
@@ -194,7 +192,7 @@ class Footer extends AbstractComponent<Props, State> {
if (!this.didCheckForOffline) {
this.didCheckForOffline = true
if (this.state.offline && this.application.items.getNoteCount() === 0) {
this.viewControllerManager.accountMenuController.setShow(true)
this.application.accountMenuController.setShow(true)
}
}
this.findErrors()
@@ -270,7 +268,7 @@ class Footer extends AbstractComponent<Props, State> {
updateOfflineStatus() {
this.setState({
offline: this.application.noAccount(),
offline: this.application.sessions.isSignedOut(),
})
}
@@ -295,15 +293,15 @@ class Footer extends AbstractComponent<Props, State> {
}
accountMenuClickHandler = () => {
this.viewControllerManager.accountMenuController.toggleShow()
this.application.accountMenuController.toggleShow()
}
quickSettingsClickHandler = () => {
this.viewControllerManager.quickSettingsMenuController.toggle()
this.application.quickSettingsMenuController.toggle()
}
vaultSelectionClickHandler = () => {
this.viewControllerManager.vaultSelectionController.toggle()
this.application.vaultSelectionController.toggle()
}
syncResolutionClickHandler = () => {
@@ -313,8 +311,8 @@ class Footer extends AbstractComponent<Props, State> {
}
closeAccountMenu = () => {
this.viewControllerManager.accountMenuController.setShow(false)
this.viewControllerManager.accountMenuController.setCurrentPane(AccountMenuPane.GeneralMenu)
this.application.accountMenuController.setShow(false)
this.application.accountMenuController.setCurrentPane(AccountMenuPane.GeneralMenu)
}
lockClickHandler = () => {
@@ -342,19 +340,19 @@ class Footer extends AbstractComponent<Props, State> {
}
clickOutsideAccountMenu = () => {
this.viewControllerManager.accountMenuController.closeAccountMenu()
this.application.accountMenuController.closeAccountMenu()
}
clickOutsideQuickSettingsMenu = () => {
this.viewControllerManager.quickSettingsMenuController.closeQuickSettingsMenu()
this.application.quickSettingsMenuController.closeQuickSettingsMenu()
}
openPreferences = (openWhatsNew: boolean) => {
this.clickOutsideQuickSettingsMenu()
if (openWhatsNew) {
this.viewControllerManager.preferencesController.setCurrentPane('whats-new')
this.application.preferencesController.setCurrentPane('whats-new')
}
this.viewControllerManager.preferencesController.openPreferences()
this.application.preferencesController.openPreferences()
}
override render() {
@@ -367,14 +365,12 @@ class Footer extends AbstractComponent<Props, State> {
<div className="left flex h-full flex-shrink-0">
<div className="sk-app-bar-item relative z-footer-bar-item ml-0 select-none">
<AccountMenuButton
application={this.application}
hasError={this.state.hasError}
isOpen={this.state.showAccountMenu}
mainApplicationGroup={this.props.applicationGroup}
onClickOutside={this.clickOutsideAccountMenu}
toggleMenu={this.accountMenuClickHandler}
user={this.user}
viewControllerManager={this.viewControllerManager}
/>
</div>
@@ -387,7 +383,7 @@ class Footer extends AbstractComponent<Props, State> {
isOpen={this.state.showQuickSettingsMenu}
toggleMenu={this.quickSettingsClickHandler}
application={this.application}
quickSettingsMenuController={this.viewControllerManager.quickSettingsMenuController}
quickSettingsMenuController={this.application.quickSettingsMenuController}
/>
</div>
@@ -395,13 +391,13 @@ class Footer extends AbstractComponent<Props, State> {
<VaultSelectionButton
isOpen={this.state.showVaultSelectionMenu}
toggleMenu={this.vaultSelectionClickHandler}
controller={this.viewControllerManager.vaultSelectionController}
controller={this.application.vaultSelectionController}
/>
</div>
<UpgradeNow
application={this.application}
featuresController={this.viewControllerManager.featuresController}
subscriptionContoller={this.viewControllerManager.subscriptionController}
featuresController={this.application.featuresController}
subscriptionContoller={this.application.subscriptionController}
/>
{this.state.showBetaWarning && (
<Fragment>

View File

@@ -5,9 +5,12 @@ import ImportModalInitialPage from './InitialPage'
import Modal, { ModalAction } from '../Modal/Modal'
import ModalOverlay from '../Modal/ModalOverlay'
import { ImportModalController } from '@/Controllers/ImportModalController'
import { useApplication } from '../ApplicationProvider'
const ImportModal = ({ importModalController }: { importModalController: ImportModalController }) => {
const { files, setFiles, updateFile, removeFile, importer, parseAndImport, isVisible, close } = importModalController
const application = useApplication()
const { files, setFiles, updateFile, removeFile, parseAndImport, isVisible, close } = importModalController
const isReadyToImport = files.length > 0 && files.every((file) => file.status === 'ready')
const importSuccessOrError =
@@ -45,7 +48,7 @@ const ImportModal = ({ importModalController }: { importModalController: ImportM
key={file.id}
updateFile={updateFile}
removeFile={removeFile}
importer={importer}
importer={application.importer}
/>
))}
</div>

View File

@@ -1,5 +1,3 @@
import { FeaturesController } from '@/Controllers/FeaturesController'
import { FilesController } from '@/Controllers/FilesController'
import { LinkingController } from '@/Controllers/LinkingController'
import { observer } from 'mobx-react-lite'
import { useRef, useCallback } from 'react'
@@ -10,11 +8,9 @@ import LinkedItemsPanel from './LinkedItemsPanel'
type Props = {
linkingController: LinkingController
onClickPreprocessing?: () => Promise<void>
filesController: FilesController
featuresController: FeaturesController
}
const LinkedItemsButton = ({ linkingController, filesController, onClickPreprocessing, featuresController }: Props) => {
const LinkedItemsButton = ({ linkingController, onClickPreprocessing }: Props) => {
const { activeItem, isLinkingPanelOpen, setIsLinkingPanelOpen } = linkingController
const buttonRef = useRef<HTMLButtonElement>(null)
@@ -40,13 +36,7 @@ const LinkedItemsButton = ({ linkingController, filesController, onClickPreproce
open={isLinkingPanelOpen}
className="pb-2"
>
<LinkedItemsPanel
item={activeItem}
isOpen={isLinkingPanelOpen}
linkingController={linkingController}
filesController={filesController}
featuresController={featuresController}
/>
<LinkedItemsPanel item={activeItem} isOpen={isLinkingPanelOpen} />
</Popover>
</>
)

View File

@@ -1,7 +1,4 @@
import { FeatureName } from '@/Controllers/FeatureName'
import { FeaturesController } from '@/Controllers/FeaturesController'
import { FilesController } from '@/Controllers/FilesController'
import { LinkingController } from '@/Controllers/LinkingController'
import { classNames } from '@standardnotes/utils'
import { getLinkingSearchResults } from '@/Utils/Items/Search/getSearchResults'
import { observer } from 'mobx-react-lite'
@@ -15,26 +12,16 @@ import { LinkedItemsSectionItem } from './LinkedItemsSectionItem'
import { DecryptedItem } from '@standardnotes/snjs'
import { useItemLinks } from '@/Hooks/useItemLinks'
const LinkedItemsPanel = ({
linkingController,
filesController,
featuresController,
isOpen,
item,
}: {
linkingController: LinkingController
filesController: FilesController
featuresController: FeaturesController
isOpen: boolean
item: DecryptedItem
}) => {
const { linkItems, unlinkItems, activateItem, createAndAddNewTag, isEntitledToNoteLinking } = linkingController
const LinkedItemsPanel = ({ isOpen, item }: { isOpen: boolean; item: DecryptedItem }) => {
const application = useApplication()
const { linkItems, unlinkItems, activateItem, createAndAddNewTag, isEntitledToNoteLinking } =
application.linkingController
const { notesLinkedToItem, notesLinkingToItem, filesLinkedToItem, filesLinkingToItem, tagsLinkedToItem } =
useItemLinks(item)
const { entitledToFiles } = featuresController
const application = useApplication()
const { entitledToFiles } = application.featuresController
const searchInputRef = useRef<HTMLInputElement | null>(null)
const [searchQuery, setSearchQuery] = useState('')
@@ -49,11 +36,11 @@ const LinkedItemsPanel = ({
const selectAndUploadFiles = async () => {
if (!entitledToFiles) {
void featuresController.showPremiumAlert(FeatureName.Files)
void application.featuresController.showPremiumAlert(FeatureName.Files)
return
}
void filesController.selectAndUploadNewFiles((file) => {
void application.filesController.selectAndUploadNewFiles((file) => {
void linkItems(item, file)
})
}
@@ -122,7 +109,7 @@ const LinkedItemsPanel = ({
searchQuery={searchQuery}
unlinkItem={() => unlinkItems(item, link.item)}
activateItem={activateItem}
handleFileAction={filesController.handleFileAction}
handleFileAction={application.filesController.handleFileAction}
/>
))}
</div>
@@ -142,7 +129,7 @@ const LinkedItemsPanel = ({
searchQuery={searchQuery}
unlinkItem={() => unlinkItems(item, link.item)}
activateItem={activateItem}
handleFileAction={filesController.handleFileAction}
handleFileAction={application.filesController.handleFileAction}
/>
))}
</div>
@@ -166,7 +153,7 @@ const LinkedItemsPanel = ({
searchQuery={searchQuery}
unlinkItem={() => unlinkItems(item, link.item)}
activateItem={activateItem}
handleFileAction={filesController.handleFileAction}
handleFileAction={application.filesController.handleFileAction}
/>
))}
</div>
@@ -185,7 +172,7 @@ const LinkedItemsPanel = ({
searchQuery={searchQuery}
unlinkItem={() => unlinkItems(item, link.item)}
activateItem={activateItem}
handleFileAction={filesController.handleFileAction}
handleFileAction={application.filesController.handleFileAction}
/>
))}
</div>
@@ -202,7 +189,7 @@ const LinkedItemsPanel = ({
searchQuery={searchQuery}
unlinkItem={() => unlinkItems(item, link.item)}
activateItem={activateItem}
handleFileAction={filesController.handleFileAction}
handleFileAction={application.filesController.handleFileAction}
/>
))}
</div>
@@ -221,7 +208,7 @@ const LinkedItemsPanel = ({
searchQuery={searchQuery}
unlinkItem={() => unlinkItems(item, link.item)}
activateItem={activateItem}
handleFileAction={filesController.handleFileAction}
handleFileAction={application.filesController.handleFileAction}
/>
))}
</div>

View File

@@ -3,41 +3,25 @@ import { observer } from 'mobx-react-lite'
import Button from '../Button/Button'
import { useCallback } from 'react'
import FileOptionsPanel from '../FileContextMenu/FileOptionsPanel'
import { FilesController } from '@/Controllers/FilesController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { LinkingController } from '@/Controllers/LinkingController'
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
type Props = {
filesController: FilesController
selectionController: SelectedItemsController
linkingController: LinkingController
navigationController: NavigationController
itemListController: ItemListController
}
const MultipleSelectedFiles = ({
filesController,
selectionController,
linkingController,
navigationController,
}: Props) => {
const count = selectionController.selectedFilesCount
const MultipleSelectedFiles = ({ itemListController }: Props) => {
const count = itemListController.selectedFilesCount
const cancelMultipleSelection = useCallback(() => {
selectionController.cancelMultipleSelection()
}, [selectionController])
itemListController.cancelMultipleSelection()
}, [itemListController])
return (
<div className="flex h-full flex-col items-center">
<div className="flex w-full items-center justify-between p-4">
<h1 className="m-0 text-lg font-bold">{count} selected files</h1>
<div>
<FileOptionsPanel
filesController={filesController}
selectionController={selectionController}
linkingController={linkingController}
navigationController={navigationController}
/>
<FileOptionsPanel itemListController={itemListController} />
</div>
</div>
<div className="flex min-h-full w-full max-w-md flex-grow flex-col items-center justify-center">

View File

@@ -5,35 +5,19 @@ import { WebApplication } from '@/Application/WebApplication'
import PinNoteButton from '@/Components/PinNoteButton/PinNoteButton'
import Button from '../Button/Button'
import { useCallback } from 'react'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
import { LinkingController } from '@/Controllers/LinkingController'
import ChangeMultipleButton from '../ChangeEditor/ChangeMultipleButton'
type Props = {
application: WebApplication
navigationController: NavigationController
notesController: NotesController
selectionController: SelectedItemsController
historyModalController: HistoryModalController
linkingController: LinkingController
}
const MultipleSelectedNotes = ({
application,
navigationController,
notesController,
linkingController,
selectionController,
historyModalController,
}: Props) => {
const MultipleSelectedNotes = ({ application }: Props) => {
const { notesController, itemListController } = application
const count = notesController.selectedNotesCount
const cancelMultipleSelection = useCallback(() => {
selectionController.cancelMultipleSelection()
}, [selectionController])
itemListController.cancelMultipleSelection()
}, [itemListController])
return (
<div className="flex h-full flex-col items-center">
@@ -46,13 +30,7 @@ const MultipleSelectedNotes = ({
<div className="mr-3">
<PinNoteButton notesController={notesController} />
</div>
<NotesOptionsPanel
navigationController={navigationController}
notesController={notesController}
linkingController={linkingController}
historyModalController={historyModalController}
selectionController={selectionController}
/>
<NotesOptionsPanel notesController={notesController} />
</div>
</div>
<div className="flex min-h-full w-full max-w-md flex-grow flex-col items-center justify-center md:min-h-0">

View File

@@ -1,6 +1,5 @@
import { FileItem } from '@standardnotes/snjs'
import { AbstractComponent } from '@/Components/Abstract/PureComponent'
import { WebApplication } from '@/Application/WebApplication'
import MultipleSelectedNotes from '@/Components/MultipleSelectedNotes/MultipleSelectedNotes'
import MultipleSelectedFiles from '../MultipleSelectedFiles/MultipleSelectedFiles'
import { AppPaneId } from '../Panes/AppPaneMetadata'
@@ -8,6 +7,7 @@ import FileView from '../FileView/FileView'
import NoteView from '../NoteView/NoteView'
import { NoteViewController } from '../NoteView/Controller/NoteViewController'
import { FileViewController } from '../NoteView/Controller/FileViewController'
import { WebApplication } from '@/Application/WebApplication'
type State = {
showMultipleSelectedNotes: boolean
@@ -48,36 +48,32 @@ class NoteGroupView extends AbstractComponent<Props, State> {
})
this.autorun(() => {
if (!this.viewControllerManager) {
return
}
if (this.viewControllerManager && this.viewControllerManager.notesController) {
if (this.application.notesController) {
this.setState({
showMultipleSelectedNotes: this.viewControllerManager.notesController.selectedNotesCount > 1,
showMultipleSelectedNotes: this.application.notesController.selectedNotesCount > 1,
})
}
if (this.viewControllerManager.selectionController) {
if (this.application.itemListController) {
this.setState({
showMultipleSelectedFiles: this.viewControllerManager.selectionController.selectedFilesCount > 1,
showMultipleSelectedFiles: this.application.itemListController.selectedFilesCount > 1,
})
}
})
this.autorun(() => {
if (this.viewControllerManager && this.viewControllerManager.selectionController) {
if (this.application.itemListController) {
this.setState({
selectedFile: this.viewControllerManager.selectionController.selectedFiles[0],
selectedFile: this.application.itemListController.selectedFiles[0],
})
}
})
this.autorun(() => {
if (this.viewControllerManager && this.viewControllerManager.paneController) {
if (this.application.paneController) {
this.setState({
selectedPane: this.viewControllerManager.paneController.currentPane,
isInMobileView: this.viewControllerManager.paneController.isInMobileView,
selectedPane: this.application.paneController.currentPane,
isInMobileView: this.application.paneController.isInMobileView,
})
}
})
@@ -98,23 +94,9 @@ class NoteGroupView extends AbstractComponent<Props, State> {
return (
<>
{this.state.showMultipleSelectedNotes && (
<MultipleSelectedNotes
application={this.application}
selectionController={this.viewControllerManager.selectionController}
navigationController={this.viewControllerManager.navigationController}
notesController={this.viewControllerManager.notesController}
linkingController={this.viewControllerManager.linkingController}
historyModalController={this.viewControllerManager.historyModalController}
/>
)}
{this.state.showMultipleSelectedNotes && <MultipleSelectedNotes application={this.application} />}
{this.state.showMultipleSelectedFiles && (
<MultipleSelectedFiles
filesController={this.viewControllerManager.filesController}
selectionController={this.viewControllerManager.selectionController}
navigationController={this.viewControllerManager.navigationController}
linkingController={this.viewControllerManager.linkingController}
/>
<MultipleSelectedFiles itemListController={this.application.itemListController} />
)}
{shouldNotShowMultipleSelectedItems && hasControllers && (
<>
@@ -122,12 +104,7 @@ class NoteGroupView extends AbstractComponent<Props, State> {
return controller instanceof NoteViewController ? (
<NoteView key={controller.runtimeId} application={this.application} controller={controller} />
) : (
<FileView
key={controller.runtimeId}
application={this.application}
viewControllerManager={this.viewControllerManager}
file={controller.item}
/>
<FileView key={controller.runtimeId} application={this.application} file={controller.item} />
)
})}
</>

View File

@@ -1,7 +1,7 @@
import { FileItem } from '@standardnotes/models'
import { ContentType } from '@standardnotes/domain-core'
import { SNApplication } from '@standardnotes/snjs'
import { ItemViewControllerInterface } from './ItemViewControllerInterface'
import { ItemManagerInterface } from '@standardnotes/snjs'
export class FileViewController implements ItemViewControllerInterface {
public dealloced = false
@@ -9,15 +9,14 @@ export class FileViewController implements ItemViewControllerInterface {
public runtimeId = `${Math.random()}`
constructor(
private application: SNApplication,
public item: FileItem,
private items: ItemManagerInterface,
) {}
deinit() {
this.dealloced = true
this.removeStreamObserver?.()
;(this.removeStreamObserver as unknown) = undefined
;(this.application as unknown) = undefined
;(this.item as unknown) = undefined
}
@@ -26,23 +25,20 @@ export class FileViewController implements ItemViewControllerInterface {
}
private streamItems() {
this.removeStreamObserver = this.application.streamItems<FileItem>(
ContentType.TYPES.File,
({ changed, inserted }) => {
if (this.dealloced) {
return
}
this.removeStreamObserver = this.items.streamItems<FileItem>(ContentType.TYPES.File, ({ changed, inserted }) => {
if (this.dealloced) {
return
}
const files = changed.concat(inserted)
const files = changed.concat(inserted)
const matchingFile = files.find((item) => {
return item.uuid === this.item.uuid
})
const matchingFile = files.find((item) => {
return item.uuid === this.item.uuid
})
if (matchingFile) {
this.item = matchingFile
}
},
)
if (matchingFile) {
this.item = matchingFile
}
})
}
}

View File

@@ -1,9 +1,19 @@
import { WebApplication } from '@/Application/WebApplication'
import { removeFromArray } from '@standardnotes/utils'
import { FileItem, SNNote } from '@standardnotes/snjs'
import {
AlertService,
ComponentManagerInterface,
FileItem,
ItemManagerInterface,
MutatorClientInterface,
PreferenceServiceInterface,
SNNote,
SessionsClientInterface,
SyncServiceInterface,
} from '@standardnotes/snjs'
import { NoteViewController } from './NoteViewController'
import { FileViewController } from './FileViewController'
import { TemplateNoteViewControllerOptions } from './TemplateNoteViewControllerOptions'
import { IsNativeMobileWeb } from '@standardnotes/ui-services'
type ItemControllerGroupChangeCallback = (activeController: NoteViewController | FileViewController | undefined) => void
@@ -12,10 +22,19 @@ export class ItemGroupController {
changeObservers: ItemControllerGroupChangeCallback[] = []
eventObservers: (() => void)[] = []
constructor(private application: WebApplication) {}
constructor(
private items: ItemManagerInterface,
private mutator: MutatorClientInterface,
private sync: SyncServiceInterface,
private sessions: SessionsClientInterface,
private preferences: PreferenceServiceInterface,
private components: ComponentManagerInterface,
private alerts: AlertService,
private _isNativeMobileWeb: IsNativeMobileWeb,
) {}
public deinit(): void {
;(this.application as unknown) = undefined
;(this.items as unknown) = undefined
this.eventObservers.forEach((removeObserver) => {
removeObserver()
@@ -42,11 +61,32 @@ export class ItemGroupController {
let controller!: NoteViewController | FileViewController
if (context.file) {
controller = new FileViewController(this.application, context.file)
controller = new FileViewController(context.file, this.items)
} else if (context.note) {
controller = new NoteViewController(this.application, context.note)
controller = new NoteViewController(
context.note,
this.items,
this.mutator,
this.sync,
this.sessions,
this.preferences,
this.components,
this.alerts,
this._isNativeMobileWeb,
)
} else if (context.templateOptions) {
controller = new NoteViewController(this.application, undefined, context.templateOptions)
controller = new NoteViewController(
undefined,
this.items,
this.mutator,
this.sync,
this.sessions,
this.preferences,
this.components,
this.alerts,
this._isNativeMobileWeb,
context.templateOptions,
)
} else {
throw Error('Invalid input to createItemController')
}

View File

@@ -9,6 +9,7 @@ import {
SyncServiceInterface,
ItemManagerInterface,
MutatorClientInterface,
PreferenceServiceInterface,
} from '@standardnotes/snjs'
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
import { NoteViewController } from './NoteViewController'
@@ -18,24 +19,24 @@ describe('note view controller', () => {
let componentManager: SNComponentManager
beforeEach(() => {
application = {} as jest.Mocked<WebApplication>
application.streamItems = jest.fn().mockReturnValue(() => {})
application.getPreference = jest.fn().mockReturnValue(true)
application.noAccount = jest.fn().mockReturnValue(false)
application.isNativeMobileWeb = jest.fn().mockReturnValue(false)
application = {
preferences: {
getValue: jest.fn().mockReturnValue(true),
} as unknown as jest.Mocked<PreferenceServiceInterface>,
items: {
streamItems: jest.fn().mockReturnValue(() => {}),
createTemplateItem: jest.fn().mockReturnValue({} as SNNote),
} as unknown as jest.Mocked<ItemManagerInterface>,
mutator: {} as jest.Mocked<MutatorClientInterface>,
} as unknown as jest.Mocked<WebApplication>
const items = {} as jest.Mocked<ItemManagerInterface>
items.createTemplateItem = jest.fn().mockReturnValue({} as SNNote)
Object.defineProperty(application, 'items', { value: items })
application.isNativeMobileWeb = jest.fn().mockReturnValue(false)
Object.defineProperty(application, 'sync', { value: {} as jest.Mocked<SyncServiceInterface> })
application.sync.sync = jest.fn().mockReturnValue(Promise.resolve())
componentManager = {} as jest.Mocked<SNComponentManager>
Object.defineProperty(application, 'componentManager', { value: componentManager })
const mutator = {} as jest.Mocked<MutatorClientInterface>
Object.defineProperty(application, 'mutator', { value: mutator })
})
it('should create notes with plaintext note type', async () => {
@@ -43,7 +44,17 @@ describe('note view controller', () => {
.fn()
.mockReturnValue(NativeFeatureIdentifier.TYPES.PlainEditor)
const controller = new NoteViewController(application)
const controller = new NoteViewController(
undefined,
application.items,
application.mutator,
application.sync,
application.sessions,
application.preferences,
application.componentManager,
application.alerts,
application.isNativeMobileWebUseCase,
)
await controller.initialize()
expect(application.items.createTemplateItem).toHaveBeenCalledWith(
@@ -64,7 +75,17 @@ describe('note view controller', () => {
.fn()
.mockReturnValue(NativeFeatureIdentifier.TYPES.MarkdownProEditor)
const controller = new NoteViewController(application)
const controller = new NoteViewController(
undefined,
application.items,
application.mutator,
application.sync,
application.sessions,
application.preferences,
application.componentManager,
application.alerts,
application.isNativeMobileWebUseCase,
)
await controller.initialize()
expect(application.items.createTemplateItem).toHaveBeenCalledWith(
@@ -86,7 +107,18 @@ describe('note view controller', () => {
application.items.findItem = jest.fn().mockReturnValue(tag)
application.mutator.addTagToNote = jest.fn()
const controller = new NoteViewController(application, undefined, { tag: tag.uuid })
const controller = new NoteViewController(
undefined,
application.items,
application.mutator,
application.sync,
application.sessions,
application.preferences,
application.componentManager,
application.alerts,
application.isNativeMobileWebUseCase,
{ tag: tag.uuid },
)
await controller.initialize()
expect(controller['defaultTag']).toEqual(tag)
@@ -100,7 +132,17 @@ describe('note view controller', () => {
application.items.findItem = jest.fn().mockReturnValue(note)
const controller = new NoteViewController(application, note)
const controller = new NoteViewController(
note,
application.items,
application.mutator,
application.sync,
application.sessions,
application.preferences,
application.componentManager,
application.alerts,
application.isNativeMobileWebUseCase,
)
await controller.initialize()
const changePromise = Deferred()

View File

@@ -1,4 +1,3 @@
import { WebApplication } from '@/Application/WebApplication'
import { noteTypeForEditorIdentifier } from '@standardnotes/features'
import {
SNNote,
@@ -9,13 +8,23 @@ import {
PrefKey,
PayloadVaultOverrides,
} from '@standardnotes/models'
import { UuidString } from '@standardnotes/snjs'
import {
AlertService,
ComponentManagerInterface,
ItemManagerInterface,
MutatorClientInterface,
PreferenceServiceInterface,
SessionsClientInterface,
SyncServiceInterface,
UuidString,
} from '@standardnotes/snjs'
import { removeFromArray } from '@standardnotes/utils'
import { ContentType } from '@standardnotes/domain-core'
import { ItemViewControllerInterface } from './ItemViewControllerInterface'
import { TemplateNoteViewControllerOptions } from './TemplateNoteViewControllerOptions'
import { log, LoggingDomain } from '@/Logging'
import { NoteSaveFunctionParams, NoteSyncController } from '../../../Controllers/NoteSyncController'
import { IsNativeMobileWeb } from '@standardnotes/ui-services'
export type EditorValues = {
title: string
@@ -37,8 +46,15 @@ export class NoteViewController implements ItemViewControllerInterface {
private syncController!: NoteSyncController
constructor(
private application: WebApplication,
item?: SNNote,
item: SNNote | undefined,
private items: ItemManagerInterface,
private mutator: MutatorClientInterface,
private sync: SyncServiceInterface,
private sessions: SessionsClientInterface,
private preferences: PreferenceServiceInterface,
private components: ComponentManagerInterface,
private alerts: AlertService,
private _isNativeMobileWeb: IsNativeMobileWeb,
public templateNoteOptions?: TemplateNoteViewControllerOptions,
) {
if (item) {
@@ -50,10 +66,18 @@ export class NoteViewController implements ItemViewControllerInterface {
}
if (this.defaultTagUuid) {
this.defaultTag = this.application.items.findItem(this.defaultTagUuid) as SNTag
this.defaultTag = this.items.findItem(this.defaultTagUuid) as SNTag
}
this.syncController = new NoteSyncController(this.application, this.item)
this.syncController = new NoteSyncController(
this.item,
this.items,
this.mutator,
this.sessions,
this.sync,
this.alerts,
this._isNativeMobileWeb,
)
}
deinit(): void {
@@ -74,9 +98,6 @@ export class NoteViewController implements ItemViewControllerInterface {
disposer()
}
this.disposers.length = 0
;(this.application as unknown) = undefined
;(this.item as unknown) = undefined
this.innerValueChangeObservers.length = 0
}
@@ -89,16 +110,16 @@ export class NoteViewController implements ItemViewControllerInterface {
this.needsInit = false
const addTagHierarchy = this.application.getPreference(PrefKey.NoteAddToParentFolders, true)
const addTagHierarchy = this.preferences.getValue(PrefKey.NoteAddToParentFolders, true)
if (!this.item) {
log(LoggingDomain.NoteView, 'Initializing as template note')
const editorIdentifier = this.application.componentManager.getDefaultEditorIdentifier(this.defaultTag)
const editorIdentifier = this.components.getDefaultEditorIdentifier(this.defaultTag)
const noteType = noteTypeForEditorIdentifier(editorIdentifier)
const note = this.application.items.createTemplateItem<NoteContent, SNNote>(
const note = this.items.createTemplateItem<NoteContent, SNNote>(
ContentType.TYPES.Note,
{
text: '',
@@ -118,8 +139,8 @@ export class NoteViewController implements ItemViewControllerInterface {
this.syncController.setItem(this.item)
if (this.defaultTagUuid) {
const tag = this.application.items.findItem(this.defaultTagUuid) as SNTag
await this.application.mutator.addTagToNote(note, tag, addTagHierarchy)
const tag = this.items.findItem(this.defaultTagUuid) as SNTag
await this.mutator.addTagToNote(note, tag, addTagHierarchy)
}
this.notifyObservers(this.item, PayloadEmitSource.InitialObserverRegistrationPush)
@@ -140,7 +161,7 @@ export class NoteViewController implements ItemViewControllerInterface {
}
this.disposers.push(
this.application.streamItems<SNNote>(ContentType.TYPES.Note, ({ changed, inserted, source }) => {
this.items.streamItems<SNNote>(ContentType.TYPES.Note, ({ changed, inserted, source }) => {
if (this.dealloced) {
return
}
@@ -163,7 +184,7 @@ export class NoteViewController implements ItemViewControllerInterface {
public insertTemplatedNote(): Promise<DecryptedItemInterface> {
log(LoggingDomain.NoteView, 'Inserting template note')
this.isTemplateNote = false
return this.application.mutator.insertItem(this.item)
return this.mutator.insertItem(this.item)
}
/**

View File

@@ -105,7 +105,7 @@ const NoteConflictResolutionModal = ({
mutator.conflictOf = undefined
})
setIsPerformingAction(false)
void application.controllers.selectionController.selectItem(selectedNotes[0].uuid, true)
void application.itemListController.selectItem(selectedNotes[0].uuid, true)
void application.sync.sync()
close()
}

View File

@@ -3,7 +3,6 @@
*/
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import {
ApplicationEvent,
@@ -18,7 +17,7 @@ import { NoteViewController } from './Controller/NoteViewController'
describe('NoteView', () => {
let noteViewController: NoteViewController
let application: WebApplication
let viewControllerManager: ViewControllerManager
let notesController: NotesController
const createNoteView = () =>
@@ -37,13 +36,11 @@ describe('NoteView', () => {
notesController.getSpellcheckStateForNote = jest.fn()
notesController.getEditorWidthForNote = jest.fn()
viewControllerManager = {
notesController: notesController,
} as jest.Mocked<ViewControllerManager>
application = {
controllers: viewControllerManager,
} as jest.Mocked<WebApplication>
notesController,
noteViewController,
} as unknown as jest.Mocked<WebApplication>
application.hasProtectionSources = jest.fn().mockReturnValue(true)
application.authorizeNoteAccess = jest.fn()
application.addWebEventObserver = jest.fn()

View File

@@ -111,7 +111,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
if (!this.controller || this.controller.dealloced) {
return
}
this.application.getDesktopService()?.redoSearch()
this.application.desktopManager?.redoSearch()
}
this.debounceReloadEditorComponent = debounce(this.debounceReloadEditorComponent.bind(this), 25)
@@ -215,7 +215,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
this.autorun(() => {
this.setState({
showProtectedWarning: this.viewControllerManager.notesController.showProtectedWarning,
showProtectedWarning: this.application.notesController.showProtectedWarning,
})
})
@@ -224,7 +224,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
const showProtectedWarning =
this.note.protected &&
(!this.application.hasProtectionSources() || !this.application.hasUnprotectedAccessSession())
(!this.application.hasProtectionSources() || !this.application.protections.hasUnprotectedAccessSession())
this.setShowProtectedOverlay(showProtectedWarning)
this.reloadPreferences().catch(console.error)
@@ -429,7 +429,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
}
streamItems() {
this.removeNoteStreamObserver = this.application.streamItems<SNNote>(ContentType.TYPES.Note, async () => {
this.removeNoteStreamObserver = this.application.items.streamItems<SNNote>(ContentType.TYPES.Note, async () => {
if (!this.note) {
return
}
@@ -541,7 +541,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
})
this.setStatus({
type: 'saved',
message: 'All changes saved' + (this.application.noAccount() ? ' offline' : ''),
message: 'All changes saved' + (this.application.sessions.isSignedOut() ? ' offline' : ''),
})
}
@@ -615,7 +615,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
}
setShowProtectedOverlay(show: boolean) {
this.viewControllerManager.notesController.setShowProtectedWarning(show)
this.application.notesController.setShowProtectedWarning(show)
}
async deleteNote(permanently: boolean) {
@@ -677,7 +677,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
}
async reloadSpellcheck() {
const spellcheck = this.viewControllerManager.notesController.getSpellcheckStateForNote(this.note)
const spellcheck = this.application.notesController.getSpellcheckStateForNote(this.note)
if (spellcheck !== this.state.spellcheck) {
reloadFont(this.state.monospaceFont)
this.setState({ spellcheck })
@@ -685,7 +685,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
}
reloadLineWidth() {
const editorLineWidth = this.viewControllerManager.notesController.getEditorWidthForNote(this.note)
const editorLineWidth = this.application.notesController.getEditorWidthForNote(this.note)
this.setState({
editorLineWidth,
@@ -849,15 +849,15 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
{this.note && (
<NoteViewFileDropTarget
note={this.note}
linkingController={this.viewControllerManager.linkingController}
filesController={this.viewControllerManager.filesController}
linkingController={this.application.linkingController}
filesController={this.application.filesController}
noteViewElement={this.noteViewElementRef.current}
/>
)}
{this.state.noteLocked && (
<EditingDisabledBanner
onClick={() => this.viewControllerManager.notesController.setLockSelectedNotes(!this.state.noteLocked)}
onClick={() => this.application.notesController.setLockSelectedNotes(!this.state.noteLocked)}
noteLocked={this.state.noteLocked}
/>
)}
@@ -913,36 +913,26 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
<div className="note-view-options-buttons flex items-center gap-3">
<CollaborationInfoHUD item={this.note} />
<LinkedItemsButton
filesController={this.viewControllerManager.filesController}
linkingController={this.viewControllerManager.linkingController}
linkingController={this.application.linkingController}
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
featuresController={this.viewControllerManager.featuresController}
/>
<ChangeEditorButton
viewControllerManager={this.viewControllerManager}
noteViewController={this.controller}
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
/>
<PinNoteButton
notesController={this.viewControllerManager.notesController}
notesController={this.application.notesController}
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
/>
<NotesOptionsPanel
navigationController={this.viewControllerManager.navigationController}
notesController={this.viewControllerManager.notesController}
linkingController={this.viewControllerManager.linkingController}
historyModalController={this.viewControllerManager.historyModalController}
selectionController={this.viewControllerManager.selectionController}
notesController={this.application.notesController}
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
/>
</div>
)}
</div>
<div className="hidden md:block">
<LinkedItemBubblesContainer
item={this.note}
linkingController={this.viewControllerManager.linkingController}
/>
<LinkedItemBubblesContainer item={this.note} linkingController={this.application.linkingController} />
</div>
</div>
)}
@@ -990,8 +980,8 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
<SuperEditor
key={this.note.uuid}
application={this.application}
linkingController={this.viewControllerManager.linkingController}
filesController={this.viewControllerManager.filesController}
linkingController={this.application.linkingController}
filesController={this.application.filesController}
spellcheck={this.state.spellcheck}
controller={this.controller}
/>

View File

@@ -24,7 +24,7 @@ const NoteViewFileDropTarget = ({ note, linkingController, noteViewElement, file
tooltipText: 'Drop your files to upload and link them to the current note',
callback: async (uploadedFile) => {
await linkingController.linkItems(note, uploadedFile)
void application.changeAndSaveItem(uploadedFile, (mutator) => {
void application.changeAndSaveItem.execute(uploadedFile, (mutator) => {
mutator.protected = note.protected
})
filesController.notifyObserversOfUploadedFileLinkingToCurrentNote(uploadedFile.uuid)

View File

@@ -46,6 +46,7 @@ export const PlainEditor = forwardRef<PlainEditorInterface, Props>(
const note = useRef(controller.item)
const tabObserverDisposer = useRef<Disposer>()
const mutationObserver = useRef<MutationObserver | null>(null)
useImperativeHandle(ref, () => ({
focus() {
@@ -53,6 +54,15 @@ export const PlainEditor = forwardRef<PlainEditorInterface, Props>(
},
}))
useEffect(() => {
return () => {
mutationObserver.current?.disconnect()
tabObserverDisposer.current?.()
tabObserverDisposer.current = undefined
mutationObserver.current = null
}
}, [])
useEffect(() => {
const disposer = controller.addNoteInnerValueChangeObserver((updatedNote, source) => {
if (updatedNote.uuid !== note.current.uuid) {
@@ -219,15 +229,18 @@ export const PlainEditor = forwardRef<PlainEditorInterface, Props>(
const observer = new MutationObserver((records) => {
for (const record of records) {
record.removedNodes.forEach((node) => {
if (node === editor) {
if (node.isEqualNode(editor)) {
tabObserverDisposer.current?.()
tabObserverDisposer.current = undefined
observer.disconnect()
}
})
}
})
observer.observe(editor.parentElement as HTMLElement, { childList: true })
mutationObserver.current = observer
}
if (textareaUnloading) {

View File

@@ -1,30 +1,14 @@
import { observer } from 'mobx-react-lite'
import NotesOptions from '@/Components/NotesOptions/NotesOptions'
import { useCallback, useState } from 'react'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
import Popover from '../Popover/Popover'
import { LinkingController } from '@/Controllers/LinkingController'
import Menu from '../Menu/Menu'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import { useApplication } from '../ApplicationProvider'
type Props = {
navigationController: NavigationController
notesController: NotesController
linkingController: LinkingController
historyModalController: HistoryModalController
selectionController: SelectedItemsController
}
const NotesContextMenu = () => {
const application = useApplication()
const NotesContextMenu = ({
navigationController,
notesController,
linkingController,
historyModalController,
selectionController,
}: Props) => {
const { contextMenuOpen, contextMenuClickLocation, setContextMenuOpen } = notesController
const { contextMenuOpen, contextMenuClickLocation, setContextMenuOpen } = application.notesController
const closeMenu = () => setContextMenuOpen(!contextMenuOpen)
@@ -48,12 +32,7 @@ const NotesContextMenu = ({
>
<Menu className="select-none" a11yLabel="Note context menu" isOpen={contextMenuOpen}>
<NotesOptions
notes={notesController.selectedNotes}
navigationController={navigationController}
notesController={notesController}
linkingController={linkingController}
historyModalController={historyModalController}
selectionController={selectionController}
notes={application.notesController.selectedNotes}
requestDisableClickOutside={handleDisableClickOutsideRequest}
closeMenu={closeMenu}
/>

View File

@@ -50,15 +50,7 @@ const iconClassDanger = `text-danger mr-2 ${iconSize}`
const iconClassWarning = `text-warning mr-2 ${iconSize}`
const iconClassSuccess = `text-success mr-2 ${iconSize}`
const NotesOptions = ({
notes,
navigationController,
notesController,
linkingController,
selectionController,
historyModalController,
closeMenu,
}: NotesOptionsProps) => {
const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => {
const application = useApplication()
const [altKeyDown, setAltKeyDown] = useState(false)
@@ -117,7 +109,7 @@ const NotesOptions = ({
if (notes.length === 1) {
const note = notes[0]
const blob = getNoteBlob(application, note)
application.getArchiveService().downloadData(blob, getNoteFileName(application, note))
application.archiveService.downloadData(blob, getNoteFileName(application, note))
return
}
@@ -126,7 +118,7 @@ const NotesOptions = ({
type: ToastType.Loading,
message: `Exporting ${notes.length} notes...`,
})
await application.getArchiveService().downloadDataAsZip(
await application.archiveService.downloadDataAsZip(
notes.map((note) => {
return {
name: getNoteFileName(application, note),
@@ -163,7 +155,7 @@ const NotesOptions = ({
{
label: 'Open',
handler: (toastId) => {
selectionController.selectItem(duplicated.uuid, true).catch(console.error)
application.itemListController.selectItem(duplicated.uuid, true).catch(console.error)
dismissToast(toastId)
},
},
@@ -176,11 +168,11 @@ const NotesOptions = ({
)
void application.sync.sync()
closeMenuAndToggleNotesList()
}, [application.mutator, application.sync, closeMenuAndToggleNotesList, notes, selectionController])
}, [application.mutator, application.itemListController, application.sync, closeMenuAndToggleNotesList, notes])
const openRevisionHistoryModal = useCallback(() => {
historyModalController.openModal(notesController.firstSelectedNote)
}, [historyModalController, notesController.firstSelectedNote])
application.historyModalController.openModal(application.notesController.firstSelectedNote)
}, [application.historyModalController, application.notesController.firstSelectedNote])
const historyShortcut = useMemo(
() => application.keyboardService.keyboardShortcutForCommand(OPEN_NOTE_HISTORY_COMMAND),
@@ -243,7 +235,7 @@ const NotesOptions = ({
<MenuSwitchButtonItem
checked={locked}
onChange={(locked) => {
notesController.setLockSelectedNotes(locked)
application.notesController.setLockSelectedNotes(locked)
}}
>
<Icon type="pencil-off" className={iconClass} />
@@ -252,7 +244,7 @@ const NotesOptions = ({
<MenuSwitchButtonItem
checked={!hidePreviews}
onChange={(hidePreviews) => {
notesController.setHideSelectedNotePreviews(!hidePreviews)
application.notesController.setHideSelectedNotePreviews(!hidePreviews)
}}
>
<Icon type="rich-text" className={iconClass} />
@@ -261,7 +253,7 @@ const NotesOptions = ({
<MenuSwitchButtonItem
checked={protect}
onChange={(protect) => {
notesController.setProtectSelectedNotes(protect).catch(console.error)
application.notesController.setProtectSelectedNotes(protect).catch(console.error)
}}
>
<Icon type="lock" className={iconClass} />
@@ -277,17 +269,17 @@ const NotesOptions = ({
{featureTrunkVaultsEnabled() && <AddToVaultMenuOption iconClassName={iconClass} items={notes} />}
{navigationController.tagsCount > 0 && (
{application.navigationController.tagsCount > 0 && (
<AddTagOption
iconClassName={iconClass}
navigationController={navigationController}
navigationController={application.navigationController}
selectedItems={notes}
linkingController={linkingController}
linkingController={application.linkingController}
/>
)}
<MenuItem
onClick={() => {
notesController.setStarSelectedNotes(!starred)
application.notesController.setStarSelectedNotes(!starred)
}}
>
<Icon type="star" className={iconClass} />
@@ -298,7 +290,7 @@ const NotesOptions = ({
{unpinned && (
<MenuItem
onClick={() => {
notesController.setPinSelectedNotes(true)
application.notesController.setPinSelectedNotes(true)
}}
>
<Icon type="pin" className={iconClass} />
@@ -309,7 +301,7 @@ const NotesOptions = ({
{pinned && (
<MenuItem
onClick={() => {
notesController.setPinSelectedNotes(false)
application.notesController.setPinSelectedNotes(false)
}}
>
<Icon type="unpin" className={iconClass} />
@@ -394,7 +386,7 @@ const NotesOptions = ({
{unarchived && (
<MenuItem
onClick={async () => {
await notesController.setArchiveSelectedNotes(true).catch(console.error)
await application.notesController.setArchiveSelectedNotes(true).catch(console.error)
closeMenuAndToggleNotesList()
}}
>
@@ -405,7 +397,7 @@ const NotesOptions = ({
{archived && (
<MenuItem
onClick={async () => {
await notesController.setArchiveSelectedNotes(false).catch(console.error)
await application.notesController.setArchiveSelectedNotes(false).catch(console.error)
closeMenuAndToggleNotesList()
}}
>
@@ -417,14 +409,14 @@ const NotesOptions = ({
(altKeyDown ? (
<DeletePermanentlyButton
onClick={async () => {
await notesController.deleteNotesPermanently()
await application.notesController.deleteNotesPermanently()
closeMenuAndToggleNotesList()
}}
/>
) : (
<MenuItem
onClick={async () => {
await notesController.setTrashSelectedNotes(true)
await application.notesController.setTrashSelectedNotes(true)
closeMenuAndToggleNotesList()
}}
>
@@ -436,7 +428,7 @@ const NotesOptions = ({
<>
<MenuItem
onClick={async () => {
await notesController.setTrashSelectedNotes(false)
await application.notesController.setTrashSelectedNotes(false)
closeMenuAndToggleNotesList()
}}
>
@@ -445,13 +437,13 @@ const NotesOptions = ({
</MenuItem>
<DeletePermanentlyButton
onClick={async () => {
await notesController.deleteNotesPermanently()
await application.notesController.deleteNotesPermanently()
closeMenuAndToggleNotesList()
}}
/>
<MenuItem
onClick={async () => {
await notesController.emptyTrash()
await application.notesController.emptyTrash()
closeMenuAndToggleNotesList()
}}
>
@@ -459,7 +451,7 @@ const NotesOptions = ({
<Icon type="trash-sweep" className="mr-2 text-danger" />
<div className="flex-row">
<div className="text-danger">Empty Trash</div>
<div className="text-xs">{notesController.trashedNotesCount} notes in Trash</div>
<div className="text-xs">{application.notesController.trashedNotesCount} notes in Trash</div>
</div>
</div>
</MenuItem>
@@ -482,7 +474,11 @@ const NotesOptions = ({
<HorizontalSeparator classes="my-2" />
{editorForNote && (
<SpellcheckOptions editorForNote={editorForNote} notesController={notesController} note={notes[0]} />
<SpellcheckOptions
editorForNote={editorForNote}
notesController={application.notesController}
note={notes[0]}
/>
)}
<HorizontalSeparator classes="my-2" />

View File

@@ -2,31 +2,16 @@ import { useCallback, useRef, useState } from 'react'
import { observer } from 'mobx-react-lite'
import NotesOptions from './NotesOptions'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
import Popover from '../Popover/Popover'
import { LinkingController } from '@/Controllers/LinkingController'
import RoundIconButton from '../Button/RoundIconButton'
import Menu from '../Menu/Menu'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
type Props = {
navigationController: NavigationController
notesController: NotesController
linkingController: LinkingController
historyModalController: HistoryModalController
selectionController: SelectedItemsController
onClickPreprocessing?: () => Promise<void>
}
const NotesOptionsPanel = ({
navigationController,
notesController,
linkingController,
historyModalController,
selectionController,
onClickPreprocessing,
}: Props) => {
const NotesOptionsPanel = ({ notesController, onClickPreprocessing }: Props) => {
const [isOpen, setIsOpen] = useState(false)
const buttonRef = useRef<HTMLButtonElement>(null)
@@ -57,11 +42,6 @@ const NotesOptionsPanel = ({
<Menu a11yLabel="Note options menu" isOpen={isOpen}>
<NotesOptions
notes={notesController.selectedNotes}
navigationController={navigationController}
notesController={notesController}
linkingController={linkingController}
historyModalController={historyModalController}
selectionController={selectionController}
requestDisableClickOutside={handleDisableClickOutsideRequest}
closeMenu={toggleMenu}
/>

View File

@@ -1,17 +1,7 @@
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { LinkingController } from '@/Controllers/LinkingController'
import { SNNote } from '@standardnotes/snjs'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
export type NotesOptionsProps = {
notes: SNNote[]
navigationController: NavigationController
notesController: NotesController
linkingController: LinkingController
historyModalController: HistoryModalController
selectionController: SelectedItemsController
requestDisableClickOutside?: (disabled: boolean) => void
closeMenu: () => void
}

View File

@@ -1,6 +1,5 @@
import { useCallback, useRef } from 'react'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import Button from '@/Components/Button/Button'
import Icon from '../Icon/Icon'
@@ -8,15 +7,14 @@ import AlertDialog from '../AlertDialog/AlertDialog'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const ConfirmOtherSessionsSignOut = observer(({ application, viewControllerManager }: Props) => {
const ConfirmOtherSessionsSignOut = observer(({ application }: Props) => {
const cancelRef = useRef<HTMLButtonElement>(null)
const closeDialog = useCallback(() => {
viewControllerManager.accountMenuController.setOtherSessionsSignOut(false)
}, [viewControllerManager])
application.accountMenuController.setOtherSessionsSignOut(false)
}, [application])
const confirm = useCallback(() => {
application.revokeAllOtherSessions().catch(console.error)
@@ -55,7 +53,7 @@ const ConfirmOtherSessionsSignOut = observer(({ application, viewControllerManag
ConfirmOtherSessionsSignOut.displayName = 'ConfirmOtherSessionsSignOut'
const OtherSessionsSignOutContainer = (props: Props) => {
if (!props.viewControllerManager.accountMenuController.otherSessionsSignOut) {
if (!props.application.accountMenuController.otherSessionsSignOut) {
return null
}
return <ConfirmOtherSessionsSignOut {...props} />

View File

@@ -38,8 +38,6 @@ const PanesSystemComponent = () => {
const [panesPendingEntrance, setPanesPendingEntrance] = useState<AppPaneId[]>([])
const [panesPendingExit, setPanesPendingExit] = useState<AppPaneId[]>([])
const viewControllerManager = application.controllers
const [navigationPanelWidth, setNavigationPanelWidth] = useState<number>(
application.getPreference(PrefKey.TagsPanelWidth, PLACEHOLDER_NAVIGATION_PANEL_WIDTH),
)
@@ -296,18 +294,6 @@ const PanesSystemComponent = () => {
key={'content-list-view'}
application={application}
onPanelWidthLoad={handleInitialItemsListPanelWidthLoad}
accountMenuController={viewControllerManager.accountMenuController}
filesController={viewControllerManager.filesController}
itemListController={viewControllerManager.itemListController}
navigationController={viewControllerManager.navigationController}
noAccountWarningController={viewControllerManager.noAccountWarningController}
notesController={viewControllerManager.notesController}
selectionController={viewControllerManager.selectionController}
searchOptionsController={viewControllerManager.searchOptionsController}
linkingController={viewControllerManager.linkingController}
featuresController={viewControllerManager.featuresController}
historyModalController={viewControllerManager.historyModalController}
paneController={viewControllerManager.paneController}
>
{showPanelResizers && listRef && (
<PanelResizer

View File

@@ -153,7 +153,7 @@ class PasswordWizard extends AbstractComponent<Props, State> {
return false
}
if (!this.application.getUser()?.email) {
if (!this.application.sessions.getUser()?.email) {
this.application.alerts
.alert("We don't have your email stored. Please sign out then log back in to fix this issue.")
.catch(console.error)

View File

@@ -15,39 +15,23 @@ import Vaults from './Panes/Vaults/Vaults'
const PaneSelector: FunctionComponent<PreferencesProps & { menu: PreferencesSessionController }> = ({
menu,
viewControllerManager,
application,
mfaProvider,
userProvider,
}) => {
switch (menu.selectedPaneId) {
case 'general':
return (
<General
viewControllerManager={viewControllerManager}
application={application}
extensionsLatestVersions={menu.extensionsLatestVersions}
/>
)
return <General application={application} extensionsLatestVersions={menu.extensionsLatestVersions} />
case 'account':
return <AccountPreferences application={application} viewControllerManager={viewControllerManager} />
return <AccountPreferences application={application} />
case 'appearance':
return <Appearance application={application} />
case 'home-server':
return <HomeServer />
case 'security':
return (
<Security
mfaProvider={mfaProvider}
userProvider={userProvider}
viewControllerManager={viewControllerManager}
application={application}
/>
)
return <Security application={application} />
case 'vaults':
return <Vaults />
case 'backups':
return <Backups application={application} viewControllerManager={viewControllerManager} />
return <Backups application={application} />
case 'listed':
return <Listed application={application} />
case 'shortcuts':
@@ -61,13 +45,7 @@ const PaneSelector: FunctionComponent<PreferencesProps & { menu: PreferencesSess
case 'whats-new':
return <WhatsNew application={application} />
default:
return (
<General
viewControllerManager={viewControllerManager}
application={application}
extensionsLatestVersions={menu.extensionsLatestVersions}
/>
)
return <General application={application} extensionsLatestVersions={menu.extensionsLatestVersions} />
}
}

View File

@@ -1,7 +1,6 @@
import { observer } from 'mobx-react-lite'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import Authentication from './Authentication'
import Credentials from './Credentials'
import Sync from './Sync'
@@ -15,30 +14,29 @@ import DeleteAccount from '@/Components/Preferences/Panes/Account/DeleteAccount'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const AccountPreferences = ({ application, viewControllerManager }: Props) => {
const AccountPreferences = ({ application }: Props) => {
const isUsingThirdPartyServer = application.isThirdPartyHostUsed()
return (
<PreferencesPane>
{!application.hasAccount() ? (
<Authentication application={application} viewControllerManager={viewControllerManager} />
<Authentication application={application} />
) : (
<>
<Credentials application={application} viewControllerManager={viewControllerManager} />
<Credentials application={application} />
<Sync application={application} />
</>
)}
<Subscription />
<SubscriptionSharing application={application} viewControllerManager={viewControllerManager} />
{application.hasAccount() && viewControllerManager.featuresController.entitledToFiles && (
<SubscriptionSharing application={application} />
{application.hasAccount() && application.featuresController.entitledToFiles && (
<FilesSection application={application} />
)}
{application.hasAccount() && !isUsingThirdPartyServer && <Email application={application} />}
<SignOutWrapper application={application} viewControllerManager={viewControllerManager} />
<DeleteAccount application={application} viewControllerManager={viewControllerManager} />
<SignOutWrapper application={application} />
<DeleteAccount application={application} />
</PreferencesPane>
)
}

View File

@@ -1,7 +1,6 @@
import Button from '@/Components/Button/Button'
import { Title } from '@/Components/Preferences/PreferencesComponents/Content'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'react'
import { AccountIllustration } from '@standardnotes/icons'
@@ -11,20 +10,19 @@ import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const Authentication: FunctionComponent<Props> = ({ viewControllerManager }) => {
const Authentication: FunctionComponent<Props> = ({ application }) => {
const clickSignIn = () => {
viewControllerManager.preferencesController.closePreferences()
viewControllerManager.accountMenuController.setCurrentPane(AccountMenuPane.SignIn)
viewControllerManager.accountMenuController.setShow(true)
application.preferencesController.closePreferences()
application.accountMenuController.setCurrentPane(AccountMenuPane.SignIn)
application.accountMenuController.setShow(true)
}
const clickRegister = () => {
viewControllerManager.preferencesController.closePreferences()
viewControllerManager.accountMenuController.setCurrentPane(AccountMenuPane.Register)
viewControllerManager.accountMenuController.setShow(true)
application.preferencesController.closePreferences()
application.accountMenuController.setCurrentPane(AccountMenuPane.Register)
application.accountMenuController.setShow(true)
}
return (

View File

@@ -1,14 +1,14 @@
import Button from '@/Components/Button/Button'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'react'
import { Title, Text } from '../../PreferencesComponents/Content'
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
import { useApplication } from '@/Components/ApplicationProvider'
const ClearSessionDataView: FunctionComponent = () => {
const application = useApplication()
const ClearSessionDataView: FunctionComponent<{
viewControllerManager: ViewControllerManager
}> = ({ viewControllerManager }) => {
return (
<PreferencesGroup>
<PreferencesSegment>
@@ -18,7 +18,7 @@ const ClearSessionDataView: FunctionComponent<{
colorStyle="danger"
label="Clear workspace"
onClick={() => {
viewControllerManager.accountMenuController.setSigningOut(true)
application.accountMenuController.setSigningOut(true)
}}
/>
</PreferencesSegment>

View File

@@ -6,7 +6,6 @@ import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
import { dateToLocalizedString } from '@standardnotes/snjs'
import { useCallback, useState, FunctionComponent } from 'react'
import ChangeEmail from '@/Components/Preferences/Panes/Account/ChangeEmail/ChangeEmail'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import PasswordWizard from '@/Components/PasswordWizard/PasswordWizard'
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
@@ -14,14 +13,13 @@ import ModalOverlay from '@/Components/Modal/ModalOverlay'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const Credentials: FunctionComponent<Props> = ({ application }: Props) => {
const [isChangeEmailDialogOpen, setIsChangeEmailDialogOpen] = useState(false)
const [shouldShowPasswordWizard, setShouldShowPasswordWizard] = useState(false)
const user = application.getUser()
const user = application.sessions.getUser()
const passwordCreatedAtTimestamp = application.getUserPasswordCreationDate() as Date
const passwordCreatedOn = dateToLocalizedString(passwordCreatedAtTimestamp)

View File

@@ -3,15 +3,13 @@ import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/P
import { Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
import Button from '@/Components/Button/Button'
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
import { ViewControllerManager } from '@Controllers/ViewControllerManager'
import { WebApplication } from '@/Application/WebApplication'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const DeleteAccount = ({ application, viewControllerManager }: Props) => {
const DeleteAccount = ({ application }: Props) => {
if (!application.hasAccount()) {
return null
}
@@ -25,7 +23,7 @@ const DeleteAccount = ({ application, viewControllerManager }: Props) => {
colorStyle="danger"
label="Delete my account"
onClick={() => {
viewControllerManager.accountMenuController.setDeletingAccount(true)
application.accountMenuController.setDeletingAccount(true)
}}
/>
</div>

View File

@@ -43,7 +43,7 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
}
const loadSettings = useCallback(async () => {
if (!application.getUser()) {
if (!application.sessions.getUser()) {
return
}
setIsLoading(true)

View File

@@ -2,7 +2,6 @@ import Button from '@/Components/Button/Button'
import OtherSessionsSignOutContainer from '@/Components/OtherSessionsSignOut/OtherSessionsSignOut'
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'react'
import { Subtitle, Title, Text } from '../../PreferencesComponents/Content'
@@ -12,10 +11,9 @@ import ClearSessionDataView from './ClearSessionDataView'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const SignOutView: FunctionComponent<Props> = observer(({ application, viewControllerManager }) => {
const SignOutView: FunctionComponent<Props> = observer(({ application }) => {
return (
<>
<PreferencesGroup>
@@ -27,10 +25,10 @@ const SignOutView: FunctionComponent<Props> = observer(({ application, viewContr
<Button
label="Sign out other sessions"
onClick={() => {
viewControllerManager.accountMenuController.setOtherSessionsSignOut(true)
application.accountMenuController.setOtherSessionsSignOut(true)
}}
/>
<Button label="Manage sessions" onClick={() => viewControllerManager.openSessionsModal()} />
<Button label="Manage sessions" onClick={() => application.openSessionsModal()} />
</div>
</PreferencesSegment>
<HorizontalSeparator classes="my-4" />
@@ -42,23 +40,23 @@ const SignOutView: FunctionComponent<Props> = observer(({ application, viewContr
colorStyle="danger"
label="Sign out workspace"
onClick={() => {
viewControllerManager.accountMenuController.setSigningOut(true)
application.accountMenuController.setSigningOut(true)
}}
/>
</PreferencesSegment>
</PreferencesGroup>
<OtherSessionsSignOutContainer viewControllerManager={viewControllerManager} application={application} />
<OtherSessionsSignOutContainer application={application} />
</>
)
})
SignOutView.displayName = 'SignOutView'
const SignOutWrapper: FunctionComponent<Props> = ({ application, viewControllerManager }) => {
const SignOutWrapper: FunctionComponent<Props> = ({ application }) => {
if (!application.hasAccount()) {
return <ClearSessionDataView viewControllerManager={viewControllerManager} />
return <ClearSessionDataView />
}
return <SignOutView viewControllerManager={viewControllerManager} application={application} />
return <SignOutView application={application} />
}
export default observer(SignOutWrapper)

View File

@@ -12,16 +12,16 @@ const Subscription: FunctionComponent = () => {
const application = useApplication()
const [onlineSubscription, setOnlineSubscription] = useState<Subscription | undefined>(
application.controllers.subscriptionController.onlineSubscription,
application.subscriptionController.onlineSubscription,
)
useEffect(() => {
return application.subscriptions.addEventObserver((event) => {
if (event === SubscriptionManagerEvent.DidFetchSubscription) {
setOnlineSubscription(application.controllers.subscriptionController.onlineSubscription)
setOnlineSubscription(application.subscriptionController.onlineSubscription)
}
})
}, [application.subscriptions, application.controllers.subscriptionController])
}, [application.subscriptions, application.subscriptionController])
useEffect(() => {
void application.subscriptions.fetchOnlineSubscription()

View File

@@ -1,6 +1,5 @@
import { observer } from 'mobx-react-lite'
import Button from '@/Components/Button/Button'
import { openSubscriptionDashboard } from '@/Utils/ManageSubscription'
import SubscriptionStatusText from './SubscriptionStatusText'
import { useApplication } from '@/Components/ApplicationProvider'
@@ -8,7 +7,7 @@ const SubscriptionInformation = () => {
const application = useApplication()
const manageSubscription = async () => {
void openSubscriptionDashboard(application)
void application.openSubscriptionDashboard.execute()
}
return (

View File

@@ -1,10 +1,8 @@
import { FeatureStatus, NativeFeatureIdentifier } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useState } from 'react'
import { Title } from '@/Components/Preferences/PreferencesComponents/Content'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
@@ -18,13 +16,12 @@ import ModalOverlay from '@/Components/Modal/ModalOverlay'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const SubscriptionSharing: FunctionComponent<Props> = ({ application, viewControllerManager }: Props) => {
const SubscriptionSharing: FunctionComponent<Props> = ({ application }: Props) => {
const [isInviteDialogOpen, setIsInviteDialogOpen] = useState(false)
const subscriptionState = viewControllerManager.subscriptionController
const subscriptionState = application.subscriptionController
const isReadOnlySession = application.sessions.isCurrentSessionReadOnly()

View File

@@ -1,5 +1,4 @@
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { FunctionComponent } from 'react'
import PreferencesPane from '@/Components/Preferences/PreferencesComponents/PreferencesPane'
import DataBackups from './DataBackups'
@@ -10,16 +9,15 @@ import TextBackupsCrossPlatform from './TextBackups/TextBackupsCrossPlatform'
import PlaintextBackupsCrossPlatform from './PlaintextBackups/PlaintextBackupsCrossPlatform'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
}
const Backups: FunctionComponent<Props> = ({ application, viewControllerManager }) => {
const Backups: FunctionComponent<Props> = ({ application }) => {
const isUsingThirdPartyServer = application.isThirdPartyHostUsed()
return (
<PreferencesPane>
<DataBackups application={application} viewControllerManager={viewControllerManager} />
<DataBackups application={application} />
<TextBackupsCrossPlatform application={application} />
<PlaintextBackupsCrossPlatform />
<FileBackupsCrossPlatform application={application} />

View File

@@ -12,7 +12,6 @@ import {
import { BackupFile } from '@standardnotes/snjs'
import { ChangeEventHandler, MouseEventHandler, useCallback, useEffect, useRef, useState } from 'react'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { Title, Subtitle } from '@/Components/Preferences/PreferencesComponents/Content'
import Button from '@/Components/Button/Button'
@@ -24,10 +23,9 @@ import { downloadOrShareBlobBasedOnPlatform } from '@/Utils/DownloadOrShareBased
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const DataBackups = ({ application, viewControllerManager }: Props) => {
const DataBackups = ({ application }: Props) => {
const fileInputRef = useRef<HTMLInputElement>(null)
const [isImportDataLoading, setIsImportDataLoading] = useState(false)
const {
@@ -36,7 +34,7 @@ const DataBackups = ({ application, viewControllerManager }: Props) => {
setIsBackupEncrypted,
setIsEncryptionEnabled,
setEncryptionStatusString,
} = viewControllerManager.accountMenuController
} = application.accountMenuController
const refreshEncryptionStatus = useCallback(() => {
const hasUser = application.hasAccount()
@@ -73,16 +71,30 @@ const DataBackups = ({ application, viewControllerManager }: Props) => {
})
if (isBackupEncrypted) {
const filename = `Standard Notes Encrypted Backup and Import File - ${application
.getArchiveService()
.formattedDateForExports()}`
const filename = `Standard Notes Encrypted Backup and Import File - ${application.archiveService.formattedDateForExports()}`
const sanitizedFilename = sanitizeFileName(filename) + '.txt'
void downloadOrShareBlobBasedOnPlatform(application, blobData, sanitizedFilename)
void downloadOrShareBlobBasedOnPlatform({
archiveService: application.archiveService,
platform: application.platform,
mobileDevice: application.mobileDevice,
blob: blobData,
filename: sanitizedFilename,
isNativeMobileWeb: application.isNativeMobileWeb(),
showToastOnAndroid: undefined,
})
} else {
const zippedDecryptedItemsBlob = await application.getArchiveService().getZippedDecryptedItemsBlob(data)
const filename = `Standard Notes Backup - ${application.getArchiveService().formattedDateForExports()}`
const zippedDecryptedItemsBlob = await application.archiveService.getZippedDecryptedItemsBlob(data)
const filename = `Standard Notes Backup - ${application.archiveService.formattedDateForExports()}`
const sanitizedFilename = sanitizeFileName(filename) + '.zip'
void downloadOrShareBlobBasedOnPlatform(application, zippedDecryptedItemsBlob, sanitizedFilename)
void downloadOrShareBlobBasedOnPlatform({
archiveService: application.archiveService,
platform: application.platform,
mobileDevice: application.mobileDevice,
blob: zippedDecryptedItemsBlob,
filename: sanitizedFilename,
isNativeMobileWeb: application.isNativeMobileWeb(),
showToastOnAndroid: undefined,
})
}
}

View File

@@ -25,7 +25,7 @@ const EmailBackups = ({ application }: Props) => {
const hasAccount = application.hasAccount()
const loadEmailFrequencySetting = useCallback(async () => {
if (!application.getUser()) {
if (!application.sessions.getUser()) {
return
}
setIsLoading(true)

View File

@@ -41,7 +41,7 @@ const TextBackupsDesktop = ({ backupsService }: Props) => {
}, [backupsEnabled, backupsService])
const performBackup = useCallback(async () => {
void application.getDesktopService()?.saveDesktopBackup()
void application.desktopManager?.saveDesktopBackup()
}, [application])
return (

View File

@@ -2,7 +2,6 @@ import { FunctionComponent } from 'react'
import OfflineSubscription from '@/Components/Preferences/Panes/General/Advanced/OfflineSubscription'
import { WebApplication } from '@/Application/WebApplication'
import { observer } from 'mobx-react-lite'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import PackagesPreferencesSection from '@/Components/Preferences/Panes/General/Advanced/Packages/Section'
import { PackageProvider } from '@/Components/Preferences/Panes/General/Advanced/Packages/Provider/PackageProvider'
import AccordionItem from '@/Components/Shared/AccordionItem'
@@ -11,18 +10,17 @@ import PreferencesSegment from '../../../PreferencesComponents/PreferencesSegmen
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
extensionsLatestVersions: PackageProvider
}
const Advanced: FunctionComponent<Props> = ({ application, viewControllerManager, extensionsLatestVersions }) => {
const Advanced: FunctionComponent<Props> = ({ application, extensionsLatestVersions }) => {
return (
<PreferencesGroup>
<PreferencesSegment>
<AccordionItem title={'Advanced options'}>
<div className="flex flex-row items-center">
<div className="flex max-w-full flex-grow flex-col">
<OfflineSubscription application={application} viewControllerManager={viewControllerManager} />
<OfflineSubscription application={application} />
<PackagesPreferencesSection
className={'mt-3'}
application={application}

View File

@@ -3,7 +3,6 @@ import { Subtitle } from '@/Components/Preferences/PreferencesComponents/Content
import DecoratedInput from '@/Components/Input/DecoratedInput'
import Button from '@/Components/Button/Button'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { STRING_REMOVE_OFFLINE_KEY_CONFIRMATION } from '@/Constants/Strings'
import { ButtonType, ClientDisplayableError } from '@standardnotes/snjs'
@@ -11,7 +10,6 @@ import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
onSuccess?: () => void
}
@@ -46,7 +44,7 @@ const OfflineSubscription: FunctionComponent<Props> = ({ application, onSuccess
return
}
const signedInUser = application.getUser()
const signedInUser = application.sessions.getUser()
if (!signedInUser) {
return
}

View File

@@ -34,12 +34,12 @@ const PackageEntry: FunctionComponent<PackageEntryProps> = ({ application, exten
const toggleOfflineOnly = () => {
const newOfflineOnly = !offlineOnly
setOfflineOnly(newOfflineOnly)
application
.changeAndSaveItem<ComponentMutator>(extension, (mutator) => {
application.changeAndSaveItem
.execute<ComponentMutator>(extension, (mutator) => {
mutator.offlineOnly = newOfflineOnly
})
.then((item) => {
const component = item as ComponentInterface
.then((result) => {
const component = result.getValue() as ComponentInterface
setOfflineOnly(component.offlineOnly)
})
.catch((e) => {
@@ -49,12 +49,12 @@ const PackageEntry: FunctionComponent<PackageEntryProps> = ({ application, exten
const changeExtensionName = (newName: string) => {
setExtensionName(newName)
application
.changeAndSaveItem<ComponentMutator>(extension, (mutator) => {
application.changeAndSaveItem
.execute<ComponentMutator>(extension, (mutator) => {
mutator.name = newName
})
.then((item) => {
const component = item as ComponentInterface
.then((result) => {
const component = result.getValue() as ComponentInterface
setExtensionName(component.name)
})
.catch(console.error)

View File

@@ -1,5 +1,4 @@
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { FunctionComponent } from 'react'
import { PackageProvider } from '@/Components/Preferences/Panes/General/Advanced/Packages/Provider/PackageProvider'
import { observer } from 'mobx-react-lite'
@@ -13,24 +12,19 @@ import SmartViews from './SmartViews/SmartViews'
import Moments from './Moments'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
extensionsLatestVersions: PackageProvider
}
const General: FunctionComponent<Props> = ({ viewControllerManager, application, extensionsLatestVersions }) => (
const General: FunctionComponent<Props> = ({ application, extensionsLatestVersions }) => (
<PreferencesPane>
<Persistence application={application} />
<Defaults application={application} />
<Tools application={application} />
<SmartViews application={application} featuresController={viewControllerManager.featuresController} />
<SmartViews application={application} featuresController={application.featuresController} />
<Moments application={application} />
<LabsPane application={application} />
<Advanced
application={application}
viewControllerManager={viewControllerManager}
extensionsLatestVersions={extensionsLatestVersions}
/>
<Advanced application={application} extensionsLatestVersions={extensionsLatestVersions} />
</PreferencesPane>
)

View File

@@ -21,9 +21,9 @@ const Persistence = ({ application }: Props) => {
setShouldPersistNoteState(shouldPersist)
if (shouldPersist) {
application.controllers.persistValues()
application.persistence.persistCurrentState()
} else {
application.controllers.clearPersistedValues()
application.persistence.clearPersistedValues()
}
}

View File

@@ -88,7 +88,7 @@ export class EditSmartViewModalController {
this.setIsSaving(true)
await this.application.changeAndSaveItem<SmartViewMutator>(this.view, (mutator) => {
await this.application.changeAndSaveItem.execute<SmartViewMutator>(this.view, (mutator) => {
mutator.title = this.title
mutator.iconString = (this.icon as string) || SmartViewDefaultIconName
mutator.predicate = JSON.parse(this.predicateJson) as PredicateJsonForm

View File

@@ -33,7 +33,7 @@ const SmartViews = ({ application, featuresController }: Props) => {
)
useEffect(() => {
const disposeItemStream = application.streamItems([ContentType.TYPES.SmartView], () => {
const disposeItemStream = application.items.streamItems([ContentType.TYPES.SmartView], () => {
setSmartViews(application.items.getSmartViews().filter((view) => !isSystemView(view)))
})

View File

@@ -9,7 +9,7 @@ import { MouseEventHandler } from 'react'
const HelpAndFeedback = ({ application }: { application: WebApplication }) => {
const openLinkOnMobile = (link: string) => {
if (application.isNativeMobileWeb()) {
application.mobileDevice().openUrl(link)
application.mobileDevice.openUrl(link)
}
}

View File

@@ -25,7 +25,6 @@ const HomeServerSettings = () => {
const homeServerService = application.homeServer as HomeServerServiceInterface
const featuresService = application.features
const sessionsService = application.sessions
const viewControllerManager = application.controllers
const logsTextarea = useRef<HTMLTextAreaElement>(null)
@@ -392,7 +391,6 @@ const HomeServerSettings = () => {
{showOfflineSubscriptionActivation && (
<OfflineSubscription
application={application}
viewControllerManager={viewControllerManager}
onSuccess={() => {
setIsAPremiumUser(true)
setShowOfflineSubscriptionActivation(false)

View File

@@ -39,7 +39,7 @@ const StatusIndicator = ({ status, className, homeServerService }: Props) => {
useEffect(() => {
async function updateSignedInStatus() {
const signedInUser = application.getUser()
const signedInUser = application.sessions.getUser()
if (signedInUser) {
const isUsingHomeServer = await application.isUsingHomeServer()
if (isUsingHomeServer) {

View File

@@ -84,13 +84,14 @@ const Listed = ({ application }: Props) => {
<Subtitle>What is Listed?</Subtitle>
<Text>
Listed is a free blogging platform that allows you to create a public journal published directly from your
notes. {!application.getUser() && 'To get started, sign in or register for a Standard Notes account.'}
notes.{' '}
{!application.sessions.getUser() && 'To get started, sign in or register for a Standard Notes account.'}
</Text>
<a className="mt-2 text-info" target="_blank" href="https://listed.to" rel="noreferrer noopener">
Learn more
</a>
</PreferencesSegment>
{application.getUser() && (
{application.sessions.getUser() && (
<>
<HorizontalSeparator classes="my-4" />
<PreferencesSegment>

View File

@@ -1,16 +1,15 @@
import { STRING_E2E_ENABLED, STRING_ENC_NOT_ENABLED, STRING_LOCAL_ENC_ENABLED } from '@/Constants/Strings'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'react'
import { Title, Text } from '../../PreferencesComponents/Content'
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
import EncryptionEnabled from './EncryptionEnabled'
import { useApplication } from '@/Components/ApplicationProvider'
type Props = { viewControllerManager: ViewControllerManager }
const Encryption: FunctionComponent = () => {
const app = useApplication()
const Encryption: FunctionComponent<Props> = ({ viewControllerManager }) => {
const app = viewControllerManager.application
const hasUser = app.hasAccount()
const hasPasscode = app.hasPasscode()
const isEncryptionEnabled = app.isEncryptionAvailable()

View File

@@ -14,7 +14,7 @@ const ErroredItems: FunctionComponent = () => {
const [erroredItems, setErroredItems] = useState(application.items.invalidNonVaultedItems)
useEffect(() => {
return application.streamItems(ContentType.TYPES.Any, () => {
return application.items.streamItems(ContentType.TYPES.Any, () => {
setErroredItems(application.items.invalidNonVaultedItems)
})
}, [application])
@@ -83,7 +83,7 @@ const ErroredItems: FunctionComponent = () => {
className="mr-2 mt-3 min-w-20"
label="Export all"
onClick={() => {
void application.getArchiveService().downloadEncryptedItems(erroredItems)
void application.archiveService.downloadEncryptedItems(erroredItems)
}}
/>
<Button
@@ -117,7 +117,7 @@ const ErroredItems: FunctionComponent = () => {
className="mr-2 mt-3 min-w-20"
label="Export"
onClick={() => {
void application.getArchiveService().downloadEncryptedItem(item)
void application.archiveService.downloadEncryptedItem(item)
}}
/>
<Button

View File

@@ -1,12 +1,12 @@
import { observer } from 'mobx-react-lite'
import { WebApplication } from '@/Application/WebApplication'
import { isIOS } from '@/Utils'
import { useEffect, useState } from 'react'
import { MobileDeviceInterface } from '@standardnotes/services'
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
import { Title } from '@/Components/Preferences/PreferencesComponents/Content'
import Button from '@/Components/Button/Button'
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
import { isIOS } from '@standardnotes/ui-services'
type Props = {
application: WebApplication

View File

@@ -14,7 +14,6 @@ import { alertDialog } from '@standardnotes/ui-services'
import { FormEvent, useCallback, useEffect, useRef, useState } from 'react'
import { ApplicationEvent, MobileUnlockTiming } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { Title, Text } from '@/Components/Preferences/PreferencesComponents/Content'
import Button from '@/Components/Button/Button'
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
@@ -24,15 +23,13 @@ import { classNames } from '@standardnotes/utils'
type Props = {
application: WebApplication
viewControllerManager: ViewControllerManager
}
const PasscodeLock = ({ application, viewControllerManager }: Props) => {
const PasscodeLock = ({ application }: Props) => {
const isNativeMobileWeb = application.isNativeMobileWeb()
const keyStorageInfo = StringUtils.keyStorageInfo(application)
const { setIsEncryptionEnabled, setIsBackupEncrypted, setEncryptionStatusString } =
viewControllerManager.accountMenuController
const { setIsEncryptionEnabled, setIsBackupEncrypted, setEncryptionStatusString } = application.accountMenuController
const passcodeInputRef = useRef<HTMLInputElement>(null)
@@ -58,7 +55,7 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
}
const reloadDesktopAutoLockInterval = useCallback(async () => {
const interval = await application.getAutolockService()?.getAutoLockInterval()
const interval = await application.autolockService?.getAutoLockInterval()
setSelectedAutoLockInterval(interval)
}, [application])
@@ -86,7 +83,7 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
return
}
await application.getAutolockService()?.setAutoLockInterval(interval)
await application.autolockService?.setAutoLockInterval(interval)
reloadDesktopAutoLockInterval().catch(console.error)
}
@@ -99,7 +96,7 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
await preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL, async () => {
if (await application.removePasscode()) {
if (!isNativeMobileWeb) {
await application.getAutolockService()?.deleteAutolockPreference()
await application.autolockService?.deleteAutolockPreference()
await reloadDesktopAutoLockInterval()
}
refreshEncryptionStatus()
@@ -184,7 +181,7 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
setPasscodeConfirmation(undefined)
}
const autolockService = application.getAutolockService()
const autolockService = application.autolockService
return (
<>

View File

@@ -30,7 +30,7 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
}
const loadSettings = useCallback(async () => {
if (!application.getUser()) {
if (!application.sessions.getUser()) {
return
}
setIsLoading(true)

View File

@@ -1,7 +1,6 @@
import { NativeFeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
import { WebApplication } from '@/Application/WebApplication'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { FunctionComponent } from 'react'
import TwoFactorAuthWrapper from './TwoFactorAuth/TwoFactorAuthWrapper'
import { MfaProps } from './TwoFactorAuth/MfaProps'
@@ -16,7 +15,6 @@ import MultitaskingPrivacy from '@/Components/Preferences/Panes/Security/Multita
import U2FWrapper from './U2F/U2FWrapper'
interface SecurityProps extends MfaProps {
viewControllerManager: ViewControllerManager
application: WebApplication
}
@@ -26,23 +24,19 @@ const Security: FunctionComponent<SecurityProps> = (props) => {
const isU2FFeatureAvailable =
props.application.features.getFeatureStatus(
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.UniversalSecondFactor).getValue(),
) === FeatureStatus.Entitled && props.userProvider.getUser() !== undefined
) === FeatureStatus.Entitled && props.application.sessions.getUser() !== undefined
return (
<PreferencesPane>
<Encryption viewControllerManager={props.viewControllerManager} />
<Encryption />
{props.application.items.invalidNonVaultedItems.length > 0 && <ErroredItems />}
<Protections application={props.application} />
<TwoFactorAuthWrapper
mfaProvider={props.mfaProvider}
userProvider={props.userProvider}
application={props.application}
/>
{isU2FFeatureAvailable && <U2FWrapper userProvider={props.userProvider} application={props.application} />}
<TwoFactorAuthWrapper application={props.application} />
{isU2FFeatureAvailable && <U2FWrapper application={props.application} />}
{isNativeMobileWeb && <MultitaskingPrivacy application={props.application} />}
<PasscodeLock viewControllerManager={props.viewControllerManager} application={props.application} />
<PasscodeLock application={props.application} />
{isNativeMobileWeb && <BiometricsLock application={props.application} />}
{props.application.getUser() && <Privacy application={props.application} />}
{props.application.sessions.getUser() && <Privacy application={props.application} />}
</PreferencesPane>
)
}

View File

@@ -1,8 +1,5 @@
import { WebApplication } from '@/Application/WebApplication'
import { MfaProvider, UserProvider } from '@/Components/Preferences/Providers'
export interface MfaProps {
userProvider: UserProvider
mfaProvider: MfaProvider
application: WebApplication
}

Some files were not shown because too many files have changed in this diff Show More