feat: display number of files for 'Files' view (#2065)

* feat: display number of files for 'Files' view

* feat: include files count in Preferences > Security
This commit is contained in:
Mo
2022-11-28 15:38:50 -06:00
committed by GitHub
parent 052e7d2f90
commit 767d354780
25 changed files with 69 additions and 91 deletions

View File

@@ -583,7 +583,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234 boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: 48289402952f4f7a4e235de70a9a590aa0b79ef4 FBLazyVector: 48289402952f4f7a4e235de70a9a590aa0b79ef4
FBReactNativeSpec: dd1186fd05255e3457baa2f4ca65e94c2cd1e3ac FBReactNativeSpec: dd1186fd05255e3457baa2f4ca65e94c2cd1e3ac
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
@@ -596,7 +596,7 @@ SPEC CHECKSUMS:
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 85ecdd10ee8d8ec362ef519a6a45ff9aa27b2e85 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
hermes-engine: 2af7b7a59128f250adfd86f15aa1d5a2ecd39995 hermes-engine: 2af7b7a59128f250adfd86f15aa1d5a2ecd39995
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c

View File

@@ -1,4 +1,3 @@
import { isNote } from './../../../Syncable/Note/Note'
import { removeFromArray } from '@standardnotes/utils' import { removeFromArray } from '@standardnotes/utils'
import { ContentType, Uuid } from '@standardnotes/common' import { ContentType, Uuid } from '@standardnotes/common'
import { isTag, SNTag } from '../../../Syncable/Tag/Tag' import { isTag, SNTag } from '../../../Syncable/Tag/Tag'
@@ -13,7 +12,7 @@ export type TagItemCountChangeObserver = (tagUuid: Uuid | AllNotesUuidSignifier)
export class TagItemsIndex implements SNIndex { export class TagItemsIndex implements SNIndex {
private tagToItemsMap: Partial<Record<Uuid, Set<Uuid>>> = {} private tagToItemsMap: Partial<Record<Uuid, Set<Uuid>>> = {}
private allCountableItems = new Set<Uuid>() private allCountableItems = new Set<Uuid>()
private allCountableNotes = new Set<Uuid>() private countableItemsByType = new Map<ContentType, Set<Uuid>>()
constructor(private collection: ItemCollection, public observers: TagItemCountChangeObserver[] = []) {} constructor(private collection: ItemCollection, public observers: TagItemCountChangeObserver[] = []) {}
@@ -44,7 +43,11 @@ export class TagItemsIndex implements SNIndex {
} }
public allCountableNotesCount(): number { public allCountableNotesCount(): number {
return this.allCountableNotes.size return this.countableItemsByType.get(ContentType.Note)?.size || 0
}
public allCountableFilesCount(): number {
return this.countableItemsByType.get(ContentType.File)?.size || 0
} }
public countableItemsForTag(tag: SNTag): number { public countableItemsForTag(tag: SNTag): number {
@@ -85,15 +88,14 @@ export class TagItemsIndex implements SNIndex {
if (isCountable) { if (isCountable) {
this.allCountableItems.add(item.uuid) this.allCountableItems.add(item.uuid)
if (isNote(item)) { if (!this.countableItemsByType.has(item.content_type)) {
this.allCountableNotes.add(item.uuid) this.countableItemsByType.set(item.content_type, new Set())
} }
this.countableItemsByType.get(item.content_type)?.add(item.uuid)
} else { } else {
this.allCountableItems.delete(item.uuid) this.allCountableItems.delete(item.uuid)
this.countableItemsByType.get(item.content_type)?.delete(item.uuid)
if (isNote(item)) {
this.allCountableNotes.delete(item.uuid)
}
} }
const associatedTagUuids = this.collection.uuidsThatReferenceUuid(item.uuid) const associatedTagUuids = this.collection.uuidsThatReferenceUuid(item.uuid)

View File

@@ -12,10 +12,7 @@ import { PayloadTimestampDefaults } from '../../Abstract/Payload'
import { FilterDisplayOptions } from '../../Runtime/Display' import { FilterDisplayOptions } from '../../Runtime/Display'
import { FileItem } from '../File' import { FileItem } from '../File'
export function BuildSmartViews( export function BuildSmartViews(options: FilterDisplayOptions): SmartView[] {
options: FilterDisplayOptions,
{ supportsFileNavigation = false }: { supportsFileNavigation: boolean },
): SmartView[] {
const notes = new SmartView( const notes = new SmartView(
new DecryptedPayload({ new DecryptedPayload({
uuid: SystemViewId.AllNotes, uuid: SystemViewId.AllNotes,
@@ -88,11 +85,7 @@ export function BuildSmartViews(
}), }),
) )
if (supportsFileNavigation) { return [notes, files, starred, archived, trash, untagged]
return [notes, starred, files, archived, trash, untagged]
} else {
return [notes, starred, archived, trash, untagged]
}
} }
function allNotesPredicate(options: FilterDisplayOptions) { function allNotesPredicate(options: FilterDisplayOptions) {

View File

@@ -60,6 +60,7 @@ export interface ItemsClientInterface {
addNoteCountChangeObserver(observer: TagItemCountChangeObserver): () => void addNoteCountChangeObserver(observer: TagItemCountChangeObserver): () => void
allCountableNotesCount(): number allCountableNotesCount(): number
allCountableFilesCount(): number
countableNotesForTag(tag: SNTag | SmartView): number countableNotesForTag(tag: SNTag | SmartView): number

View File

@@ -1383,7 +1383,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
} }
private createItemManager() { private createItemManager() {
this.itemManager = new InternalServices.ItemManager(this.payloadManager, this.options, this.internalEventBus) this.itemManager = new InternalServices.ItemManager(this.payloadManager, this.internalEventBus)
this.services.push(this.itemManager) this.services.push(this.itemManager)
} }

View File

@@ -1,11 +1,9 @@
import { ApplicationDisplayOptions, ApplicationSyncOptions } from './OptionalOptions' import { ApplicationSyncOptions } from './OptionalOptions'
export interface ApplicationOptionsWhichHaveDefaults { export interface ApplicationOptionsWhichHaveDefaults {
loadBatchSize: ApplicationSyncOptions['loadBatchSize'] loadBatchSize: ApplicationSyncOptions['loadBatchSize']
supportsFileNavigation: ApplicationDisplayOptions['supportsFileNavigation']
} }
export const ApplicationOptionsDefaults: ApplicationOptionsWhichHaveDefaults = { export const ApplicationOptionsDefaults: ApplicationOptionsWhichHaveDefaults = {
loadBatchSize: 700, loadBatchSize: 700,
supportsFileNavigation: false,
} }

View File

@@ -5,9 +5,8 @@ export interface ApplicationSyncOptions {
loadBatchSize: number loadBatchSize: number
} }
export interface ApplicationDisplayOptions { // eslint-disable-next-line @typescript-eslint/no-empty-interface
supportsFileNavigation: boolean export interface ApplicationDisplayOptions {}
}
export interface ApplicationOptionalConfiguratioOptions { export interface ApplicationOptionalConfiguratioOptions {
/** /**

View File

@@ -83,6 +83,7 @@ export class SNActionsService extends AbstractService {
;(this.challengeService as unknown) = undefined ;(this.challengeService as unknown) = undefined
;(this.protocolService as unknown) = undefined ;(this.protocolService as unknown) = undefined
;(this.syncService as unknown) = undefined ;(this.syncService as unknown) = undefined
this.payloadRequestHandlers.length = 0
this.previousPasswords.length = 0 this.previousPasswords.length = 0
super.deinit() super.deinit()
} }

View File

@@ -49,7 +49,7 @@ describe('itemManager', () => {
let internalEventBus: InternalEventBusInterface let internalEventBus: InternalEventBusInterface
const createService = () => { const createService = () => {
return new ItemManager(payloadManager, { supportsFileNavigation: false }, internalEventBus) return new ItemManager(payloadManager, internalEventBus)
} }
beforeEach(() => { beforeEach(() => {

View File

@@ -8,7 +8,6 @@ import * as Models from '@standardnotes/models'
import * as Services from '@standardnotes/services' import * as Services from '@standardnotes/services'
import { PayloadManagerChangeData } from '../Payloads' import { PayloadManagerChangeData } from '../Payloads'
import { DiagnosticInfo, ItemsClientInterface, ItemRelationshipDirection } from '@standardnotes/services' import { DiagnosticInfo, ItemsClientInterface, ItemRelationshipDirection } from '@standardnotes/services'
import { ApplicationDisplayOptions } from '@Lib/Application/Options/OptionalOptions'
import { CollectionSort, DecryptedItemInterface, ItemContent, SmartViewDefaultIconName } from '@standardnotes/models' import { CollectionSort, DecryptedItemInterface, ItemContent, SmartViewDefaultIconName } from '@standardnotes/models'
type ItemsChangeObserver<I extends Models.DecryptedItemInterface = Models.DecryptedItemInterface> = { type ItemsChangeObserver<I extends Models.DecryptedItemInterface = Models.DecryptedItemInterface> = {
@@ -44,7 +43,6 @@ export class ItemManager
constructor( constructor(
private payloadManager: PayloadManager, private payloadManager: PayloadManager,
private readonly options: ApplicationDisplayOptions = { supportsFileNavigation: false },
protected override internalEventBus: Services.InternalEventBusInterface, protected override internalEventBus: Services.InternalEventBusInterface,
) { ) {
super(internalEventBus) super(internalEventBus)
@@ -55,7 +53,7 @@ export class ItemManager
} }
private rebuildSystemSmartViews(criteria: Models.FilterDisplayOptions): Models.SmartView[] { private rebuildSystemSmartViews(criteria: Models.FilterDisplayOptions): Models.SmartView[] {
this.systemSmartViews = Models.BuildSmartViews(criteria, this.options) this.systemSmartViews = Models.BuildSmartViews(criteria)
return this.systemSmartViews return this.systemSmartViews
} }
@@ -68,7 +66,7 @@ export class ItemManager
{ {
sortBy: 'created_at', sortBy: 'created_at',
sortDirection: 'dsc', sortDirection: 'dsc',
hiddenContentTypes: !this.options.supportsFileNavigation ? [ContentType.File] : [], hiddenContentTypes: [],
}, },
) )
this.tagDisplayController = new Models.ItemDisplayController(this.collection, [ContentType.Tag], { this.tagDisplayController = new Models.ItemDisplayController(this.collection, [ContentType.Tag], {
@@ -184,12 +182,7 @@ export class ItemManager
public getDisplayableNotes(): Models.SNNote[] { public getDisplayableNotes(): Models.SNNote[] {
assert(this.navigationDisplayController.contentTypes.length === 2) assert(this.navigationDisplayController.contentTypes.length === 2)
const fileContentTypeHidden = !this.options.supportsFileNavigation return this.navigationDisplayController.items().filter(Models.isNote)
if (fileContentTypeHidden) {
return this.navigationDisplayController.items() as Models.SNNote[]
} else {
return this.navigationDisplayController.items().filter(Models.isNote)
}
} }
public getDisplayableFiles(): Models.FileItem[] { public getDisplayableFiles(): Models.FileItem[] {
@@ -197,7 +190,6 @@ export class ItemManager
} }
public getDisplayableNotesAndFiles(): (Models.SNNote | Models.FileItem)[] { public getDisplayableNotesAndFiles(): (Models.SNNote | Models.FileItem)[] {
assert(this.options.supportsFileNavigation)
return this.navigationDisplayController.items() return this.navigationDisplayController.items()
} }
@@ -215,7 +207,6 @@ export class ItemManager
public override deinit(): void { public override deinit(): void {
this.unsubChangeObserver() this.unsubChangeObserver()
;(this.options as unknown) = undefined
;(this.unsubChangeObserver as unknown) = undefined ;(this.unsubChangeObserver as unknown) = undefined
;(this.payloadManager as unknown) = undefined ;(this.payloadManager as unknown) = undefined
;(this.collection as unknown) = undefined ;(this.collection as unknown) = undefined
@@ -292,6 +283,10 @@ export class ItemManager
return this.tagItemsIndex.allCountableNotesCount() return this.tagItemsIndex.allCountableNotesCount()
} }
public allCountableFilesCount(): number {
return this.tagItemsIndex.allCountableFilesCount()
}
public countableNotesForTag(tag: Models.SNTag | Models.SmartView): number { public countableNotesForTag(tag: Models.SNTag | Models.SmartView): number {
if (tag instanceof Models.SmartView) { if (tag instanceof Models.SmartView) {
if (tag.uuid === Models.SystemViewId.AllNotes) { if (tag.uuid === Models.SystemViewId.AllNotes) {

View File

@@ -36,7 +36,7 @@ describe('mutator service', () => {
internalEventBus.publish = jest.fn() internalEventBus.publish = jest.fn()
payloadManager = new PayloadManager(internalEventBus) payloadManager = new PayloadManager(internalEventBus)
itemManager = new ItemManager(payloadManager, { supportsFileNavigation: false }, internalEventBus) itemManager = new ItemManager(payloadManager, internalEventBus)
mutatorService = new MutatorService( mutatorService = new MutatorService(
itemManager, itemManager,

View File

@@ -7,7 +7,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
### Bug Fixes ### Bug Fixes
* Only autofocus super notes when creating new note ([#2063](https://github.com/standardnotes/app/issues/2063)) ([96e8dfd](https://github.com/standardnotes/app/commit/96e8dfdd310fad88a360c4ac984b376b51a618d1)) * Only autofocus Super notes when creating new note ([#2063](https://github.com/standardnotes/app/issues/2063)) ([96e8dfd](https://github.com/standardnotes/app/commit/96e8dfdd310fad88a360c4ac984b376b51a618d1))
### Features ### Features

View File

@@ -74,7 +74,6 @@ export class WebApplication extends SNApplication implements WebApplicationInter
defaultHost: defaultSyncServerHost, defaultHost: defaultSyncServerHost,
appVersion: deviceInterface.appVersion, appVersion: deviceInterface.appVersion,
webSocketUrl: webSocketUrl, webSocketUrl: webSocketUrl,
supportsFileNavigation: true,
}) })
makeObservable(this, { makeObservable(this, {

View File

@@ -2,6 +2,7 @@ import { WebApplication } from '@/Application/Application'
import { FeaturesController } from '@/Controllers/FeaturesController' import { FeaturesController } from '@/Controllers/FeaturesController'
import { SubscriptionController } from '@/Controllers/Subscription/SubscriptionController' import { SubscriptionController } from '@/Controllers/Subscription/SubscriptionController'
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import { useCallback } from 'react'
type Props = { type Props = {
application: WebApplication application: WebApplication
@@ -13,13 +14,13 @@ const UpgradeNow = ({ application, featuresController, subscriptionContoller }:
const shouldShowCTA = !featuresController.hasFolders const shouldShowCTA = !featuresController.hasFolders
const hasAccount = subscriptionContoller.hasAccount const hasAccount = subscriptionContoller.hasAccount
const onClick = () => { const onClick = useCallback(() => {
if (application.isNativeIOS()) { if (hasAccount && application.isNativeIOS()) {
application.showPremiumModal() application.showPremiumModal()
} else { } else {
application.openPurchaseFlow() application.openPurchaseFlow()
} }
} }, [application, hasAccount])
return shouldShowCTA ? ( return shouldShowCTA ? (
<div className="flex h-full items-center px-2"> <div className="flex h-full items-center px-2">

View File

@@ -27,7 +27,7 @@ const Encryption: FunctionComponent<Props> = ({ viewControllerManager }) => {
<Title>Encryption</Title> <Title>Encryption</Title>
<Text>{encryptionStatusString}</Text> <Text>{encryptionStatusString}</Text>
{isEncryptionEnabled && <EncryptionEnabled viewControllerManager={viewControllerManager} />} {isEncryptionEnabled && <EncryptionEnabled />}
</PreferencesSegment> </PreferencesSegment>
</PreferencesGroup> </PreferencesGroup>
) )

View File

@@ -1,34 +1,37 @@
import { useApplication } from '@/Components/ApplicationView/ApplicationProvider'
import Icon from '@/Components/Icon/Icon' import Icon from '@/Components/Icon/Icon'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager' import { ContentType, ItemCounter } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'react' import { FunctionComponent } from 'react'
import EncryptionStatusItem from './EncryptionStatusItem' import EncryptionStatusItem from './EncryptionStatusItem'
import { formatCount } from './formatCount' import { formatCount } from './formatCount'
type Props = { const EncryptionEnabled: FunctionComponent = () => {
viewControllerManager: ViewControllerManager const application = useApplication()
} const itemCounter = new ItemCounter()
const count = itemCounter.countNotesAndTags(application.items.getItems([ContentType.Note, ContentType.Tag]))
const EncryptionEnabled: FunctionComponent<Props> = ({ viewControllerManager }) => { const files = application.items.getItems([ContentType.File])
const count = viewControllerManager.accountMenuController.structuredNotesAndTagsCount
const notes = formatCount(count.notes, 'notes') const notes = formatCount(count.notes, 'notes')
const tags = formatCount(count.tags, 'tags') const tags = formatCount(count.tags, 'tags')
const archived = formatCount(count.archived, 'archived notes') const archived = formatCount(count.archived, 'archived notes')
const deleted = formatCount(count.deleted, 'trashed notes') const deleted = formatCount(count.deleted, 'trashed notes')
const filesCount = formatCount(files.length, 'files')
const noteIcon = <Icon type="rich-text" className="min-h-5 min-w-5" /> const noteIcon = <Icon type="rich-text" className="min-h-5 min-w-5" />
const tagIcon = <Icon type="hashtag" className="min-h-5 min-w-5" /> const tagIcon = <Icon type="hashtag" className="min-h-5 min-w-5" />
const archiveIcon = <Icon type="archive" className="min-h-5 min-w-5" /> const archiveIcon = <Icon type="archive" className="min-h-5 min-w-5" />
const trashIcon = <Icon type="trash" className="min-h-5 min-w-5" /> const trashIcon = <Icon type="trash" className="min-h-5 min-w-5" />
const filesIcon = <Icon type="folder" className="min-h-5 min-w-5" />
return ( return (
<> <>
<div className="flex flex-row flex-wrap items-start pt-1.5 md:pb-1"> <div className="flex flex-row flex-wrap items-start pt-1.5 md:pb-1">
<EncryptionStatusItem status={notes} icon={noteIcon} /> <EncryptionStatusItem status={notes} icon={noteIcon} />
<div className="min-w-3" /> <div className="min-w-3" />
<EncryptionStatusItem status={filesCount} icon={filesIcon} />
<div className="min-w-3" />
<EncryptionStatusItem status={tags} icon={tagIcon} /> <EncryptionStatusItem status={tags} icon={tagIcon} />
</div> <div className="min-w-3" />
<div className="flex flex-row flex-wrap items-start">
<EncryptionStatusItem status={archived} icon={archiveIcon} /> <EncryptionStatusItem status={archived} icon={archiveIcon} />
<div className="min-w-3" /> <div className="min-w-3" />
<EncryptionStatusItem status={deleted} icon={trashIcon} /> <EncryptionStatusItem status={deleted} icon={trashIcon} />

View File

@@ -1 +1 @@
export const formatCount = (count: number, itemType: string) => `${count} / ${count} ${itemType}` export const formatCount = (count: number, itemType: string) => `${count} ${itemType}`

View File

@@ -10,7 +10,6 @@ type Props = {
application: WebApplication application: WebApplication
featureName?: FeatureName | string featureName?: FeatureName | string
hasSubscription: boolean hasSubscription: boolean
hasAccount: boolean
onClose: () => void onClose: () => void
showModal: boolean showModal: boolean
type: PremiumFeatureModalType type: PremiumFeatureModalType
@@ -20,7 +19,6 @@ const PremiumFeaturesModal: FunctionComponent<Props> = ({
application, application,
featureName, featureName,
hasSubscription, hasSubscription,
hasAccount,
onClose, onClose,
showModal, showModal,
type = PremiumFeatureModalType.UpgradePrompt, type = PremiumFeatureModalType.UpgradePrompt,
@@ -40,7 +38,6 @@ const PremiumFeaturesModal: FunctionComponent<Props> = ({
featureName={featureName} featureName={featureName}
ctaRef={ctaButtonRef} ctaRef={ctaButtonRef}
application={application} application={application}
hasAccount={hasAccount}
hasSubscription={hasSubscription} hasSubscription={hasSubscription}
onClose={onClose} onClose={onClose}
/> />

View File

@@ -10,26 +10,22 @@ export const UpgradePrompt = ({
ctaRef, ctaRef,
application, application,
hasSubscription, hasSubscription,
hasAccount,
onClose, onClose,
}: { }: {
featureName?: string featureName?: string
ctaRef: React.RefObject<HTMLButtonElement> ctaRef: React.RefObject<HTMLButtonElement>
application: WebApplication application: WebApplication
hasSubscription: boolean hasSubscription: boolean
hasAccount: boolean
onClose: () => void onClose: () => void
}) => { }) => {
const handleClick = useCallback(() => { const handleClick = useCallback(() => {
if (hasSubscription) { if (hasSubscription) {
void openSubscriptionDashboard(application) void openSubscriptionDashboard(application)
} else if (hasAccount) { } else {
void application.openPurchaseFlow() void application.openPurchaseFlow()
} else if (window.plansUrl) {
window.location.assign(window.plansUrl)
} }
onClose() onClose()
}, [application, hasSubscription, hasAccount, onClose]) }, [application, hasSubscription, onClose])
return ( return (
<> <>

View File

@@ -140,6 +140,7 @@ const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState, setEdit
)} )}
<div className={'count text-base lg:text-sm'}> <div className={'count text-base lg:text-sm'}>
{view.uuid === SystemViewId.AllNotes && tagsState.allNotesCount} {view.uuid === SystemViewId.AllNotes && tagsState.allNotesCount}
{view.uuid === SystemViewId.Files && tagsState.allFilesCount}
</div> </div>
</div> </div>

View File

@@ -8,7 +8,7 @@ export const STRING_DEFAULT_FILE_ERROR =
'Please use FileSafe or the Bold Editor to attach images and files. Learn more at standardnotes.com/filesafe.' 'Please use FileSafe or the Bold Editor to attach images and files. Learn more at standardnotes.com/filesafe.'
export const STRING_GENERIC_SYNC_ERROR = export const STRING_GENERIC_SYNC_ERROR =
'There was an error syncing. Please try again. If all else fails, try signing out and signing back in.' 'There was an error syncing. Please try again. If all else fails, try signing out and signing back in.'
export function StringSyncException(data: any) { export function StringSyncException(data: unknown) {
return `There was an error while trying to save your items. Please contact support and share this message: ${JSON.stringify( return `There was an error while trying to save your items. Please contact support and share this message: ${JSON.stringify(
data, data,
)}.` )}.`
@@ -108,7 +108,6 @@ export const STRING_FAILED_TO_UPDATE_USER_SETTING =
export const Strings = { export const Strings = {
protectingNoteWithoutProtectionSources: protectingNoteWithoutProtectionSources:
'Access to this note will not be restricted until you set up a passcode or account.', 'Access to this note will not be restricted until you set up a passcode or account.',
openAccountMenu: 'Open Account Menu',
trashItemsTitle: 'Move to Trash', trashItemsTitle: 'Move to Trash',
trashNotesText: 'Are you sure you want to move these notes to the trash?', trashNotesText: 'Are you sure you want to move these notes to the trash?',
trashFilesText: 'Are you sure you want to move these files to the trash?', trashFilesText: 'Are you sure you want to move these files to the trash?',

View File

@@ -1,14 +1,6 @@
import { destroyAllObjectProperties, isDev } from '@/Utils' import { destroyAllObjectProperties, isDev } from '@/Utils'
import { action, computed, makeObservable, observable, runInAction } from 'mobx' import { action, computed, makeObservable, observable, runInAction } from 'mobx'
import { import { ApplicationEvent, ContentType, InternalEventBus, SNNote, SNTag } from '@standardnotes/snjs'
ApplicationEvent,
ContentType,
InternalEventBus,
SNNote,
SNTag,
ItemCounterInterface,
ItemCounts,
} from '@standardnotes/snjs'
import { WebApplication } from '@/Application/Application' import { WebApplication } from '@/Application/Application'
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane' import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane'
import { AbstractViewController } from '../Abstract/AbstractViewController' import { AbstractViewController } from '../Abstract/AbstractViewController'
@@ -36,7 +28,7 @@ export class AccountMenuController extends AbstractViewController {
destroyAllObjectProperties(this) destroyAllObjectProperties(this)
} }
constructor(application: WebApplication, eventBus: InternalEventBus, private itemCounter: ItemCounterInterface) { constructor(application: WebApplication, eventBus: InternalEventBus) {
super(application, eventBus) super(application, eventBus)
makeObservable(this, { makeObservable(this, {
@@ -165,8 +157,4 @@ export class AccountMenuController extends AbstractViewController {
get notesAndTagsCount(): number { get notesAndTagsCount(): number {
return this.notesAndTags.length return this.notesAndTags.length
} }
get structuredNotesAndTagsCount(): ItemCounts {
return this.itemCounter.countNotesAndTags(this.notesAndTags)
}
} }

View File

@@ -34,6 +34,7 @@ export class NavigationController
smartViews: SmartView[] = [] smartViews: SmartView[] = []
starredTags: SNTag[] = [] starredTags: SNTag[] = []
allNotesCount_ = 0 allNotesCount_ = 0
allFilesCount_ = 0
selectedUuid: AnyTag['uuid'] | undefined = undefined selectedUuid: AnyTag['uuid'] | undefined = undefined
selected_: AnyTag | undefined = undefined selected_: AnyTag | undefined = undefined
selectedLocation: TagListSectionType | undefined = undefined selectedLocation: TagListSectionType | undefined = undefined
@@ -62,8 +63,11 @@ export class NavigationController
starredTags: observable, starredTags: observable,
smartViews: observable.ref, smartViews: observable.ref,
allNotesCount_: observable, allNotesCount_: observable,
allFilesCount_: observable,
allNotesCount: computed, allNotesCount: computed,
allFilesCount: computed,
setAllNotesCount: action, setAllNotesCount: action,
setAllFilesCount: action,
selected_: observable, selected_: observable,
selectedLocation: observable, selectedLocation: observable,
@@ -135,6 +139,7 @@ export class NavigationController
this.application.items.addNoteCountChangeObserver((tagUuid) => { this.application.items.addNoteCountChangeObserver((tagUuid) => {
if (!tagUuid) { if (!tagUuid) {
this.setAllNotesCount(this.application.items.allCountableNotesCount()) this.setAllNotesCount(this.application.items.allCountableNotesCount())
this.setAllFilesCount(this.application.items.allCountableFilesCount())
} else { } else {
const tag = this.application.items.findItem<SNTag>(tagUuid) const tag = this.application.items.findItem<SNTag>(tagUuid)
if (tag) { if (tag) {
@@ -411,6 +416,14 @@ export class NavigationController
this.allNotesCount_ = allNotesCount this.allNotesCount_ = allNotesCount
} }
setAllFilesCount(allFilesCount: number) {
this.allFilesCount_ = allFilesCount
}
public get allFilesCount(): number {
return this.allFilesCount_
}
public get allNotesCount(): number { public get allNotesCount(): number {
return this.allNotesCount_ return this.allNotesCount_
} }

View File

@@ -14,8 +14,6 @@ import {
DeinitSource, DeinitSource,
WebOrDesktopDeviceInterface, WebOrDesktopDeviceInterface,
InternalEventBus, InternalEventBus,
ItemCounterInterface,
ItemCounter,
SubscriptionClientInterface, SubscriptionClientInterface,
InternalEventHandlerInterface, InternalEventHandlerInterface,
InternalEventInterface, InternalEventInterface,
@@ -74,7 +72,6 @@ export class ViewControllerManager implements InternalEventHandlerInterface {
private appEventObserverRemovers: (() => void)[] = [] private appEventObserverRemovers: (() => void)[] = []
private eventBus: InternalEventBus private eventBus: InternalEventBus
private itemCounter: ItemCounterInterface
private subscriptionManager: SubscriptionClientInterface private subscriptionManager: SubscriptionClientInterface
private persistenceService: PersistenceService private persistenceService: PersistenceService
private applicationEventObserver: EventObserverInterface private applicationEventObserver: EventObserverInterface
@@ -88,8 +85,6 @@ export class ViewControllerManager implements InternalEventHandlerInterface {
this.eventBus.addEventHandler(this, CrossControllerEvent.HydrateFromPersistedValues) this.eventBus.addEventHandler(this, CrossControllerEvent.HydrateFromPersistedValues)
this.eventBus.addEventHandler(this, CrossControllerEvent.RequestValuePersistence) this.eventBus.addEventHandler(this, CrossControllerEvent.RequestValuePersistence)
this.itemCounter = new ItemCounter()
this.subscriptionManager = application.subscriptions this.subscriptionManager = application.subscriptions
this.quickSettingsMenuController = new QuickSettingsController(application, this.eventBus) this.quickSettingsMenuController = new QuickSettingsController(application, this.eventBus)
@@ -135,7 +130,7 @@ export class ViewControllerManager implements InternalEventHandlerInterface {
this.noAccountWarningController = new NoAccountWarningController(application, this.eventBus) this.noAccountWarningController = new NoAccountWarningController(application, this.eventBus)
this.accountMenuController = new AccountMenuController(application, this.eventBus, this.itemCounter) this.accountMenuController = new AccountMenuController(application, this.eventBus)
this.subscriptionController = new SubscriptionController(application, this.eventBus, this.subscriptionManager) this.subscriptionController = new SubscriptionController(application, this.eventBus, this.subscriptionManager)

View File

@@ -34,8 +34,6 @@ const PremiumModalProvider: FunctionComponent<Props> = observer(
const hasSubscription = application.hasValidSubscription() const hasSubscription = application.hasValidSubscription()
const hasAccount = application.hasAccount()
const activate = useCallback( const activate = useCallback(
(feature: string) => { (feature: string) => {
featuresController.showPremiumAlert(feature).catch(console.error) featuresController.showPremiumAlert(feature).catch(console.error)
@@ -54,7 +52,6 @@ const PremiumModalProvider: FunctionComponent<Props> = observer(
application={application} application={application}
featureName={featureName} featureName={featureName}
hasSubscription={hasSubscription} hasSubscription={hasSubscription}
hasAccount={hasAccount}
onClose={close} onClose={close}
showModal={featuresController.premiumAlertType != undefined} showModal={featuresController.premiumAlertType != undefined}
type={featuresController.premiumAlertType} type={featuresController.premiumAlertType}