refactor: optimize delay between batches on mobile to allow UI interactivity during load (#2129)

This commit is contained in:
Mo
2023-01-04 13:31:45 -06:00
committed by GitHub
parent 69b2af7612
commit 59fc68296b
32 changed files with 171 additions and 67 deletions

View File

@@ -78,7 +78,11 @@ export class WebApplication extends SNApplication implements WebApplicationInter
appVersion: deviceInterface.appVersion,
webSocketUrl: webSocketUrl,
loadBatchSize:
deviceInterface.environment === Environment.Mobile ? 100 : ApplicationOptionsDefaults.loadBatchSize,
deviceInterface.environment === Environment.Mobile ? 250 : ApplicationOptionsDefaults.loadBatchSize,
sleepBetweenBatches:
deviceInterface.environment === Environment.Mobile ? 250 : ApplicationOptionsDefaults.sleepBetweenBatches,
allowMultipleSelection: deviceInterface.environment !== Environment.Mobile,
allowNoteSelectionStatePersistence: deviceInterface.environment !== Environment.Mobile,
})
makeObservable(this, {

View File

@@ -14,7 +14,6 @@ import { ApplicationGroup } from '@/Application/ApplicationGroup'
import { formatLastSyncDate } from '@/Utils/DateUtils'
import Spinner from '@/Components/Spinner/Spinner'
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
type Props = {
viewControllerManager: ViewControllerManager
@@ -85,22 +84,9 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
setMenuPane(AccountMenuPane.SignIn)
}, [setMenuPane])
const openFileSend = useCallback(() => {
const link = 'https://filesend.standardnotes.com/'
if (application.isNativeMobileWeb()) {
application.mobileDevice().openUrl(link)
return
}
window.open(link, '_blank')
}, [application])
const CREATE_ACCOUNT_INDEX = 1
const SWITCHER_INDEX = 0
const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
return (
<>
<div className="mt-1 mb-1 flex items-center justify-between px-3">
@@ -186,12 +172,6 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
</div>
<span className="text-neutral">v{application.version}</span>
</MenuItem>
{isMobileScreen && (
<MenuItem onClick={openFileSend}>
<Icon type="open-in" className={iconClassName} />
Open FileSend
</MenuItem>
)}
<MenuItem onClick={() => viewControllerManager.isImportModalVisible.set(true)}>
<Icon type="archive" className={iconClassName} />
Import

View File

@@ -89,7 +89,7 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
return
}
void application.sessions.populateSessionFromDemoShareToken(token)
void application.user.populateSessionFromDemoShareToken(token)
}, [application])
const onAppLaunch = useCallback(() => {

View File

@@ -11,15 +11,17 @@ import { ItemListController } from './ItemListController'
import { ItemsReloadSource } from './ItemsReloadSource'
describe('item list controller', () => {
let application: WebApplication
let controller: ItemListController
let navigationController: NavigationController
let selectionController: SelectedItemsController
beforeEach(() => {
const application = {} as jest.Mocked<WebApplication>
application = {} as jest.Mocked<WebApplication>
application.streamItems = jest.fn()
application.addEventObserver = jest.fn()
application.addWebEventObserver = jest.fn()
application.isNativeMobileWeb = jest.fn().mockReturnValue(false)
navigationController = {} as jest.Mocked<NavigationController>
selectionController = {} as jest.Mocked<SelectedItemsController>
@@ -50,6 +52,12 @@ describe('item list controller', () => {
})
})
it('should return false is platform is native mobile web', () => {
application.isNativeMobileWeb = jest.fn().mockReturnValue(true)
expect(controller.shouldSelectFirstItem(ItemsReloadSource.TagChange)).toBe(false)
})
it('should return false first item is file', () => {
controller.getFirstNonProtectedItem = jest.fn().mockReturnValue({
content_type: ContentType.File,

View File

@@ -414,6 +414,10 @@ export class ItemListController extends AbstractViewController implements Intern
}
shouldSelectFirstItem = (itemsReloadSource: ItemsReloadSource) => {
if (this.application.isNativeMobileWeb()) {
return false
}
const item = this.getFirstNonProtectedItem()
if (item && isFile(item)) {
return false

View File

@@ -196,10 +196,13 @@ export class NavigationController
}
hydrateFromPersistedValue = (state: NavigationControllerPersistableValue | undefined) => {
if (!state) {
const uuidsToPreventHydrationOf: string[] = [SystemViewId.Files]
if (!state || uuidsToPreventHydrationOf.includes(state.selectedTagUuid)) {
void this.selectHomeNavigationView()
return
}
if (state.selectedTagUuid) {
this.selectedUuid = state.selectedTagUuid
this.selectHydratedTagOrDefault()

View File

@@ -11,6 +11,7 @@ import {
InternalEventBus,
isFile,
Uuids,
isNote,
} from '@standardnotes/snjs'
import { SelectionControllerPersistableValue } from '@standardnotes/ui-services'
import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'
@@ -77,8 +78,14 @@ export class SelectedItemsController
if (!state) {
return
}
if (!this.selectedUuids.size && state.selectedUuids.length > 0) {
void this.selectUuids(state.selectedUuids)
if (!this.application.options.allowNoteSelectionStatePersistence) {
const items = this.application.items.findItems(state.selectedUuids).filter((item) => !isNote(item))
void this.selectUuids(Uuids(items))
} else {
void this.selectUuids(state.selectedUuids)
}
}
}
@@ -264,20 +271,22 @@ export class SelectedItemsController
log(LoggingDomain.Selection, 'Select item', item.uuid)
const supportsMultipleSelection = this.application.options.allowMultipleSelection
const hasMeta = this.keyboardService.activeModifiers.has(KeyboardModifier.Meta)
const hasCtrl = this.keyboardService.activeModifiers.has(KeyboardModifier.Ctrl)
const hasShift = this.keyboardService.activeModifiers.has(KeyboardModifier.Shift)
const hasMoreThanOneSelected = this.selectedItemsCount > 1
const isAuthorizedForAccess = await this.application.protections.authorizeItemAccess(item)
if (userTriggered && (hasMeta || hasCtrl)) {
if (supportsMultipleSelection && userTriggered && (hasMeta || hasCtrl)) {
if (this.selectedUuids.has(uuid) && hasMoreThanOneSelected) {
this.removeSelectedItem(uuid)
} else if (isAuthorizedForAccess) {
this.setSelectedUuids(this.selectedUuids.add(uuid))
this.selectedUuids.add(uuid)
this.setSelectedUuids(this.selectedUuids)
this.lastSelectedItem = item
}
} else if (userTriggered && hasShift) {
} else if (supportsMultipleSelection && userTriggered && hasShift) {
await this.selectItemsRange({ selectedItem: item })
} else {
const shouldSelectNote = hasMoreThanOneSelected || !this.selectedUuids.has(uuid)