refactor(web): dependency management (#2386)
This commit is contained in:
@@ -1,19 +1,13 @@
|
||||
import { WebApplicationInterface } from './../../WebApplication/WebApplicationInterface'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { AegisToAuthenticatorConverter } from './AegisToAuthenticatorConverter'
|
||||
import data from './testData'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
|
||||
UuidGenerator.SetGenerator(() => String(Math.random()))
|
||||
|
||||
describe('AegisConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue('test'),
|
||||
} as unknown as WebApplicationInterface
|
||||
})
|
||||
|
||||
it('should parse entries', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
const converter = new AegisToAuthenticatorConverter()
|
||||
|
||||
const result = converter.parseEntries(data)
|
||||
|
||||
@@ -34,7 +28,7 @@ describe('AegisConverter', () => {
|
||||
})
|
||||
|
||||
it('should create note from entries with editor info', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
const converter = new AegisToAuthenticatorConverter()
|
||||
|
||||
const parsedEntries = converter.parseEntries(data)
|
||||
|
||||
@@ -61,7 +55,7 @@ describe('AegisConverter', () => {
|
||||
})
|
||||
|
||||
it('should create note from entries without editor info', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
const converter = new AegisToAuthenticatorConverter()
|
||||
|
||||
const parsedEntries = converter.parseEntries(data)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
|
||||
type AegisData = {
|
||||
db: {
|
||||
@@ -27,9 +27,11 @@ type AuthenticatorEntry = {
|
||||
}
|
||||
|
||||
export class AegisToAuthenticatorConverter {
|
||||
constructor(protected application: WebApplicationInterface) {}
|
||||
constructor() {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
static isValidAegisJson(json: any): boolean {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return json.db && json.db.entries && json.db.entries.every((entry: any) => AegisEntryTypes.includes(entry.type))
|
||||
}
|
||||
|
||||
@@ -61,7 +63,7 @@ export class AegisToAuthenticatorConverter {
|
||||
created_at_timestamp: file.lastModified,
|
||||
updated_at: new Date(file.lastModified),
|
||||
updated_at_timestamp: file.lastModified,
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: file.name.split('.')[0],
|
||||
|
||||
@@ -6,7 +6,7 @@ import { ContentType } from '@standardnotes/domain-core'
|
||||
import { DecryptedTransferPayload, NoteContent, TagContent } from '@standardnotes/models'
|
||||
import { EvernoteConverter } from './EvernoteConverter'
|
||||
import data from './testData'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
|
||||
// Mock dayjs so dayjs.extend() doesn't throw an error in EvernoteConverter.ts
|
||||
jest.mock('dayjs', () => {
|
||||
@@ -21,17 +21,11 @@ jest.mock('dayjs', () => {
|
||||
}
|
||||
})
|
||||
|
||||
UuidGenerator.SetGenerator(() => String(Math.random()))
|
||||
|
||||
describe('EvernoteConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue(Math.random()),
|
||||
} as any as WebApplicationInterface
|
||||
})
|
||||
|
||||
it('should parse and strip html', () => {
|
||||
const converter = new EvernoteConverter(application)
|
||||
const converter = new EvernoteConverter()
|
||||
|
||||
const result = converter.parseENEXData(data, true)
|
||||
|
||||
@@ -51,7 +45,7 @@ describe('EvernoteConverter', () => {
|
||||
})
|
||||
|
||||
it('should parse and not strip html', () => {
|
||||
const converter = new EvernoteConverter(application)
|
||||
const converter = new EvernoteConverter()
|
||||
|
||||
const result = converter.parseENEXData(data, false)
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@ import { readFileAsText } from '../Utils'
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
dayjs.extend(customParseFormat)
|
||||
dayjs.extend(utc)
|
||||
|
||||
const dateFormat = 'YYYYMMDDTHHmmss'
|
||||
|
||||
export class EvernoteConverter {
|
||||
constructor(protected application: WebApplicationInterface) {}
|
||||
constructor() {}
|
||||
|
||||
async convertENEXFileToNotesAndTags(file: File, stripHTML: boolean): Promise<DecryptedTransferPayload[]> {
|
||||
const content = await readFileAsText(file)
|
||||
@@ -35,7 +35,7 @@ export class EvernoteConverter {
|
||||
created_at_timestamp: now.getTime(),
|
||||
updated_at: now,
|
||||
updated_at_timestamp: now.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Tag,
|
||||
content: {
|
||||
title: defaultTagName,
|
||||
@@ -88,7 +88,7 @@ export class EvernoteConverter {
|
||||
created_at_timestamp: createdAtDate.getTime(),
|
||||
updated_at: updatedAtDate,
|
||||
updated_at_timestamp: updatedAtDate.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: !title ? `Imported note ${index + 1} from Evernote` : title,
|
||||
@@ -111,7 +111,7 @@ export class EvernoteConverter {
|
||||
if (!tag) {
|
||||
const now = new Date()
|
||||
tag = {
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Tag,
|
||||
created_at: now,
|
||||
created_at_timestamp: now.getTime(),
|
||||
|
||||
@@ -4,19 +4,13 @@
|
||||
|
||||
import { jsonTestData, htmlTestData } from './testData'
|
||||
import { GoogleKeepConverter } from './GoogleKeepConverter'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
|
||||
UuidGenerator.SetGenerator(() => String(Math.random()))
|
||||
|
||||
describe('GoogleKeepConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue('uuid'),
|
||||
} as unknown as WebApplicationInterface
|
||||
})
|
||||
|
||||
it('should parse json data', () => {
|
||||
const converter = new GoogleKeepConverter(application)
|
||||
const converter = new GoogleKeepConverter()
|
||||
|
||||
const result = converter.tryParseAsJson(jsonTestData)
|
||||
|
||||
@@ -33,7 +27,7 @@ describe('GoogleKeepConverter', () => {
|
||||
})
|
||||
|
||||
it('should parse html data', () => {
|
||||
const converter = new GoogleKeepConverter(application)
|
||||
const converter = new GoogleKeepConverter()
|
||||
|
||||
const result = converter.tryParseAsHtml(
|
||||
htmlTestData,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
|
||||
type GoogleKeepJsonNote = {
|
||||
color: string
|
||||
@@ -14,7 +14,7 @@ type GoogleKeepJsonNote = {
|
||||
}
|
||||
|
||||
export class GoogleKeepConverter {
|
||||
constructor(protected application: WebApplicationInterface) {}
|
||||
constructor() {}
|
||||
|
||||
async convertGoogleKeepBackupFileToNote(
|
||||
file: File,
|
||||
@@ -66,7 +66,7 @@ export class GoogleKeepConverter {
|
||||
created_at_timestamp: date.getTime(),
|
||||
updated_at: date,
|
||||
updated_at_timestamp: date.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: title,
|
||||
@@ -96,6 +96,7 @@ export class GoogleKeepConverter {
|
||||
return
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
static isValidGoogleKeepJson(json: any): boolean {
|
||||
return (
|
||||
typeof json.title === 'string' &&
|
||||
@@ -120,7 +121,7 @@ export class GoogleKeepConverter {
|
||||
created_at_timestamp: date.getTime(),
|
||||
updated_at: date,
|
||||
updated_at_timestamp: date.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: parsed.title,
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { parseFileName } from '@standardnotes/filepicker'
|
||||
import { FeatureStatus } from '@standardnotes/services'
|
||||
import {
|
||||
FeatureStatus,
|
||||
FeaturesClientInterface,
|
||||
ItemManagerInterface,
|
||||
MutatorClientInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { NativeFeatureIdentifier } from '@standardnotes/features'
|
||||
import { AegisToAuthenticatorConverter } from './AegisConverter/AegisToAuthenticatorConverter'
|
||||
import { EvernoteConverter } from './EvernoteConverter/EvernoteConverter'
|
||||
@@ -8,7 +13,6 @@ import { PlaintextConverter } from './PlaintextConverter/PlaintextConverter'
|
||||
import { SimplenoteConverter } from './SimplenoteConverter/SimplenoteConverter'
|
||||
import { readFileAsText } from './Utils'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { WebApplicationInterface } from '../WebApplication/WebApplicationInterface'
|
||||
|
||||
export type NoteImportType = 'plaintext' | 'evernote' | 'google-keep' | 'simplenote' | 'aegis'
|
||||
|
||||
@@ -19,12 +23,16 @@ export class Importer {
|
||||
plaintextConverter: PlaintextConverter
|
||||
evernoteConverter: EvernoteConverter
|
||||
|
||||
constructor(protected application: WebApplicationInterface) {
|
||||
this.aegisConverter = new AegisToAuthenticatorConverter(application)
|
||||
this.googleKeepConverter = new GoogleKeepConverter(application)
|
||||
this.simplenoteConverter = new SimplenoteConverter(application)
|
||||
this.plaintextConverter = new PlaintextConverter(application)
|
||||
this.evernoteConverter = new EvernoteConverter(application)
|
||||
constructor(
|
||||
private features: FeaturesClientInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private items: ItemManagerInterface,
|
||||
) {
|
||||
this.aegisConverter = new AegisToAuthenticatorConverter()
|
||||
this.googleKeepConverter = new GoogleKeepConverter()
|
||||
this.simplenoteConverter = new SimplenoteConverter()
|
||||
this.plaintextConverter = new PlaintextConverter()
|
||||
this.evernoteConverter = new EvernoteConverter()
|
||||
}
|
||||
|
||||
static detectService = async (file: File): Promise<NoteImportType | null> => {
|
||||
@@ -64,7 +72,7 @@ export class Importer {
|
||||
async getPayloadsFromFile(file: File, type: NoteImportType): Promise<DecryptedTransferPayload[]> {
|
||||
if (type === 'aegis') {
|
||||
const isEntitledToAuthenticator =
|
||||
this.application.features.getFeatureStatus(
|
||||
this.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.TokenVaultEditor).getValue(),
|
||||
) === FeatureStatus.Entitled
|
||||
return [await this.aegisConverter.convertAegisBackupFileToNote(file, isEntitledToAuthenticator)]
|
||||
@@ -85,7 +93,7 @@ export class Importer {
|
||||
const insertedItems = await Promise.all(
|
||||
payloads.map(async (payload) => {
|
||||
const content = payload.content as NoteContent
|
||||
const note = this.application.items.createTemplateItem(
|
||||
const note = this.items.createTemplateItem(
|
||||
payload.content_type,
|
||||
{
|
||||
text: content.text,
|
||||
@@ -100,7 +108,7 @@ export class Importer {
|
||||
uuid: payload.uuid,
|
||||
},
|
||||
)
|
||||
return this.application.mutator.insertItem(note)
|
||||
return this.mutator.insertItem(note)
|
||||
}),
|
||||
)
|
||||
return insertedItems
|
||||
|
||||
@@ -2,11 +2,9 @@ import { ContentType } from '@standardnotes/domain-core'
|
||||
import { parseFileName } from '@standardnotes/filepicker'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
|
||||
export class PlaintextConverter {
|
||||
constructor(protected application: WebApplicationInterface) {}
|
||||
|
||||
static isValidPlaintextFile(file: File): boolean {
|
||||
return file.type === 'text/plain' || file.type === 'text/markdown'
|
||||
}
|
||||
@@ -24,7 +22,7 @@ export class PlaintextConverter {
|
||||
created_at_timestamp: createdAtDate.getTime(),
|
||||
updated_at: updatedAtDate,
|
||||
updated_at_timestamp: updatedAtDate.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: name,
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
import { SimplenoteConverter } from './SimplenoteConverter'
|
||||
import data from './testData'
|
||||
|
||||
UuidGenerator.SetGenerator(() => String(Math.random()))
|
||||
|
||||
describe('SimplenoteConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue('uuid'),
|
||||
} as any
|
||||
})
|
||||
|
||||
it('should parse', () => {
|
||||
const converter = new SimplenoteConverter(application)
|
||||
const converter = new SimplenoteConverter()
|
||||
|
||||
const result = converter.parse(data)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
|
||||
type SimplenoteItem = {
|
||||
creationDate: string
|
||||
@@ -14,11 +14,13 @@ type SimplenoteData = {
|
||||
trashedNotes: SimplenoteItem[]
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const isSimplenoteEntry = (entry: any): boolean => entry.id && entry.content && entry.creationDate && entry.lastModified
|
||||
|
||||
export class SimplenoteConverter {
|
||||
constructor(protected application: WebApplicationInterface) {}
|
||||
constructor() {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
static isValidSimplenoteJson(json: any): boolean {
|
||||
return (
|
||||
(json.activeNotes && json.activeNotes.every(isSimplenoteEntry)) ||
|
||||
@@ -53,7 +55,7 @@ export class SimplenoteConverter {
|
||||
created_at_timestamp: createdAtDate.getTime(),
|
||||
updated_at: updatedAtDate,
|
||||
updated_at_timestamp: updatedAtDate.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title,
|
||||
|
||||
@@ -21,7 +21,7 @@ const STORAGE_KEY_AUTOLOCK_INTERVAL = 'AutoLockIntervalKey'
|
||||
export class AutolockService extends AbstractService {
|
||||
private unsubApp!: () => void
|
||||
|
||||
private pollInterval: any
|
||||
private pollInterval: ReturnType<typeof setInterval> | undefined
|
||||
private lastFocusState?: 'hidden' | 'visible'
|
||||
private lockAfterDate?: Date
|
||||
|
||||
@@ -100,7 +100,7 @@ export class AutolockService extends AbstractService {
|
||||
*/
|
||||
beginPolling() {
|
||||
this.pollInterval = setInterval(async () => {
|
||||
const locked = await this.application.isLocked()
|
||||
const locked = await this.application.protections.isLocked()
|
||||
if (!locked && this.lockAfterDate && new Date() > this.lockAfterDate) {
|
||||
this.lockApplication()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export enum PersistenceKey {
|
||||
SelectedItemsController = 'selected-items-controller',
|
||||
ItemListController = 'selected-items-controller',
|
||||
NavigationController = 'navigation-controller',
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ export type NavigationControllerPersistableValue = {
|
||||
}
|
||||
|
||||
export type PersistedStateValue = {
|
||||
[PersistenceKey.SelectedItemsController]: SelectionControllerPersistableValue
|
||||
[PersistenceKey.ItemListController]: SelectionControllerPersistableValue
|
||||
[PersistenceKey.NavigationController]: NavigationControllerPersistableValue
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export class ThemeManager extends AbstractUIServicee {
|
||||
}
|
||||
|
||||
override async onAppStart() {
|
||||
const desktopService = this.application.getDesktopService()
|
||||
const desktopService = this.application.desktopManager
|
||||
if (desktopService) {
|
||||
this.eventDisposers.push(
|
||||
desktopService.registerUpdateObserver((component) => {
|
||||
@@ -167,7 +167,7 @@ export class ThemeManager extends AbstractUIServicee {
|
||||
const useDeviceThemeSettings = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
|
||||
|
||||
if (useDeviceThemeSettings) {
|
||||
const prefersDarkColorScheme = (await this.application.mobileDevice().getColorScheme()) === 'dark'
|
||||
const prefersDarkColorScheme = (await this.application.mobileDevice.getColorScheme()) === 'dark'
|
||||
this.setThemeAsPerColorScheme(prefersDarkColorScheme)
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ export class ThemeManager extends AbstractUIServicee {
|
||||
let prefersDarkColorScheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
|
||||
if (this.application.isNativeMobileWeb()) {
|
||||
prefersDarkColorScheme = (await this.application.mobileDevice().getColorScheme()) === 'dark'
|
||||
prefersDarkColorScheme = (await this.application.mobileDevice.getColorScheme()) === 'dark'
|
||||
}
|
||||
|
||||
this.setThemeAsPerColorScheme(prefersDarkColorScheme)
|
||||
@@ -340,9 +340,7 @@ export class ThemeManager extends AbstractUIServicee {
|
||||
if (this.application.isNativeMobileWeb() && !theme.layerable) {
|
||||
const packageInfo = theme.featureDescription
|
||||
setTimeout(() => {
|
||||
this.application
|
||||
.mobileDevice()
|
||||
.handleThemeSchemeChange(packageInfo.isDark ?? false, this.getBackgroundColor())
|
||||
this.application.mobileDevice.handleThemeSchemeChange(packageInfo.isDark ?? false, this.getBackgroundColor())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -366,7 +364,7 @@ export class ThemeManager extends AbstractUIServicee {
|
||||
|
||||
if (this.themesActiveInTheUI.isEmpty()) {
|
||||
if (this.application.isNativeMobileWeb()) {
|
||||
this.application.mobileDevice().handleThemeSchemeChange(false, '#ffffff')
|
||||
this.application.mobileDevice.handleThemeSchemeChange(false, '#ffffff')
|
||||
}
|
||||
this.toggleTranslucentUIColors()
|
||||
}
|
||||
|
||||
15
packages/ui-services/src/UseCase/GetItemTags.ts
Normal file
15
packages/ui-services/src/UseCase/GetItemTags.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ContentType, Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { DecryptedItemInterface, SNTag } from '@standardnotes/models'
|
||||
import { ItemManagerInterface } from '@standardnotes/services'
|
||||
|
||||
export class GetItemTags implements SyncUseCaseInterface<SNTag[]> {
|
||||
constructor(private items: ItemManagerInterface) {}
|
||||
|
||||
execute(item: DecryptedItemInterface): Result<SNTag[]> {
|
||||
return Result.ok(
|
||||
this.items.itemsReferencingItem<SNTag>(item).filter((ref) => {
|
||||
return ref.content_type === ContentType.TYPES.Tag
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { PrefDefaults, PrefKey } from '@standardnotes/models'
|
||||
import { PreferenceServiceInterface } from '@standardnotes/services'
|
||||
|
||||
export class IsGlobalSpellcheckEnabled implements SyncUseCaseInterface<boolean> {
|
||||
constructor(private preferences: PreferenceServiceInterface) {}
|
||||
|
||||
execute(): Result<boolean> {
|
||||
return Result.ok(this.preferences.getValue(PrefKey.EditorSpellcheck, PrefDefaults[PrefKey.EditorSpellcheck]))
|
||||
}
|
||||
}
|
||||
11
packages/ui-services/src/UseCase/IsMobileDevice.ts
Normal file
11
packages/ui-services/src/UseCase/IsMobileDevice.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { IsNativeMobileWeb } from './IsNativeMobileWeb'
|
||||
import { isAndroid, isIOS } from '../Utils/Utils'
|
||||
|
||||
export class IsMobileDevice implements SyncUseCaseInterface<boolean> {
|
||||
constructor(private _isNativeMobileWeb: IsNativeMobileWeb) {}
|
||||
|
||||
execute(): Result<boolean> {
|
||||
return Result.ok(this._isNativeMobileWeb.execute().getValue() || isIOS() || isAndroid())
|
||||
}
|
||||
}
|
||||
13
packages/ui-services/src/UseCase/IsNativeIOS.ts
Normal file
13
packages/ui-services/src/UseCase/IsNativeIOS.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { Environment, Platform } from '@standardnotes/models'
|
||||
|
||||
export class IsNativeIOS implements SyncUseCaseInterface<boolean> {
|
||||
constructor(
|
||||
private environment: Environment,
|
||||
private platform: Platform,
|
||||
) {}
|
||||
|
||||
execute(): Result<boolean> {
|
||||
return Result.ok(this.environment === Environment.Mobile && this.platform === Platform.Ios)
|
||||
}
|
||||
}
|
||||
10
packages/ui-services/src/UseCase/IsNativeMobileWeb.ts
Normal file
10
packages/ui-services/src/UseCase/IsNativeMobileWeb.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
|
||||
export class IsNativeMobileWeb implements SyncUseCaseInterface<boolean> {
|
||||
constructor(private environment: Environment) {}
|
||||
|
||||
execute(): Result<boolean> {
|
||||
return Result.ok(this.environment === Environment.Mobile)
|
||||
}
|
||||
}
|
||||
20
packages/ui-services/src/Utils/Utils.ts
Normal file
20
packages/ui-services/src/Utils/Utils.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Platform } from '@standardnotes/models'
|
||||
|
||||
declare global {
|
||||
interface Document {
|
||||
documentMode?: string
|
||||
}
|
||||
|
||||
interface Window {
|
||||
MSStream?: unknown
|
||||
platform?: Platform
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/9038625/detect-if-device-is-ios/9039885#9039885
|
||||
export const isIOS = () =>
|
||||
(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) ||
|
||||
(navigator.userAgent.includes('Mac') && 'ontouchend' in document && navigator.maxTouchPoints > 1) ||
|
||||
window.platform === Platform.Ios
|
||||
|
||||
export const isAndroid = () => navigator.userAgent.toLowerCase().includes('android')
|
||||
@@ -33,10 +33,6 @@ export class VaultDisplayService
|
||||
|
||||
this.options = new VaultDisplayOptions({ exclude: [], locked: [] })
|
||||
|
||||
internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultLocked)
|
||||
internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultUnlocked)
|
||||
internalEventBus.addEventHandler(this, ApplicationEvent.ApplicationStageChanged)
|
||||
|
||||
makeObservable(this, {
|
||||
options: observable,
|
||||
|
||||
@@ -48,6 +44,10 @@ export class VaultDisplayService
|
||||
unhideVault: action,
|
||||
showOnlyVault: action,
|
||||
})
|
||||
|
||||
internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultLocked)
|
||||
internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultUnlocked)
|
||||
internalEventBus.addEventHandler(this, ApplicationEvent.ApplicationStageChanged)
|
||||
}
|
||||
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import {
|
||||
ApplicationInterface,
|
||||
DesktopDeviceInterface,
|
||||
DesktopManagerInterface,
|
||||
MobileDeviceInterface,
|
||||
WebAppEvent,
|
||||
} from '@standardnotes/services'
|
||||
import { KeyboardService } from '../Keyboard/KeyboardService'
|
||||
import { RouteServiceInterface } from '../Route/RouteServiceInterface'
|
||||
|
||||
export interface WebApplicationInterface extends ApplicationInterface {
|
||||
notifyWebEvent(event: WebAppEvent, data?: unknown): void
|
||||
getDesktopService(): DesktopManagerInterface | undefined
|
||||
handleMobileEnteringBackgroundEvent(): Promise<void>
|
||||
handleMobileGainingFocusEvent(): Promise<void>
|
||||
handleMobileLosingFocusEvent(): Promise<void>
|
||||
@@ -24,10 +25,17 @@ export interface WebApplicationInterface extends ApplicationInterface {
|
||||
handleReceivedTextEvent(item: { text: string; title?: string }): Promise<void>
|
||||
handleReceivedLinkEvent(item: { link: string; title: string }): Promise<void>
|
||||
isNativeMobileWeb(): boolean
|
||||
mobileDevice(): MobileDeviceInterface
|
||||
handleAndroidBackButtonPressed(): void
|
||||
addAndroidBackHandlerEventListener(listener: () => boolean): (() => void) | undefined
|
||||
setAndroidBackHandlerFallbackListener(listener: () => boolean): void
|
||||
handleInitialMobileScreenshotPrivacy(): void
|
||||
generateUUID(): string
|
||||
checkForSecurityUpdate(): Promise<boolean>
|
||||
|
||||
get desktopManager(): DesktopManagerInterface | undefined
|
||||
get mobileDevice(): MobileDeviceInterface
|
||||
get isMobileDevice(): boolean
|
||||
get desktopDevice(): DesktopDeviceInterface | undefined
|
||||
get keyboardService(): KeyboardService
|
||||
get routeService(): RouteServiceInterface
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@ export * from './Route/RouteServiceEvent'
|
||||
export * from './Security/AutolockService'
|
||||
export * from './Storage/LocalStorage'
|
||||
|
||||
export * from './UseCase/IsGlobalSpellcheckEnabled'
|
||||
export * from './UseCase/IsNativeMobileWeb'
|
||||
export * from './UseCase/IsMobileDevice'
|
||||
export * from './UseCase/IsNativeIOS'
|
||||
export * from './UseCase/GetItemTags'
|
||||
|
||||
export * from './Theme/ThemeManager'
|
||||
export * from './Theme/GetAllThemesUseCase'
|
||||
|
||||
@@ -42,3 +48,4 @@ export * from './Vaults/VaultDisplayServiceEvent'
|
||||
export * from './Vaults/VaultDisplayServiceInterface'
|
||||
|
||||
export * from './WebApplication/WebApplicationInterface'
|
||||
export * from './Utils/Utils'
|
||||
|
||||
Reference in New Issue
Block a user