internal: incomplete vault systems behind feature flag (#2340)
This commit is contained in:
52
packages/ui-services/src/Abstract/AbstractUIService.ts
Normal file
52
packages/ui-services/src/Abstract/AbstractUIService.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { AbstractService, InternalEventBusInterface, ApplicationEvent } from '@standardnotes/services'
|
||||
import { AbstractUIServiceInterface } from './AbstractUIServiceInterface'
|
||||
import { WebApplicationInterface } from '../WebApplication/WebApplicationInterface'
|
||||
|
||||
export class AbstractUIServicee<EventName = string, EventData = unknown>
|
||||
extends AbstractService<EventName, EventData>
|
||||
implements AbstractUIServiceInterface<EventName, EventData>
|
||||
{
|
||||
private unsubApp!: () => void
|
||||
|
||||
constructor(
|
||||
protected application: WebApplicationInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
this.addAppEventObserverAfterSubclassesFinishConstructing()
|
||||
}
|
||||
|
||||
async onAppStart() {
|
||||
return
|
||||
}
|
||||
|
||||
async onAppEvent(_event: ApplicationEvent) {
|
||||
return
|
||||
}
|
||||
|
||||
private addAppEventObserverAfterSubclassesFinishConstructing() {
|
||||
setTimeout(() => {
|
||||
this.addAppEventObserver()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
private addAppEventObserver() {
|
||||
if (this.application.isStarted()) {
|
||||
void this.onAppStart()
|
||||
}
|
||||
|
||||
this.unsubApp = this.application.addEventObserver(async (event: ApplicationEvent) => {
|
||||
await this.onAppEvent(event)
|
||||
if (event === ApplicationEvent.Started) {
|
||||
void this.onAppStart()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override deinit() {
|
||||
;(this.application as unknown) = undefined
|
||||
this.unsubApp()
|
||||
;(this.unsubApp as unknown) = undefined
|
||||
super.deinit()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { ApplicationEvent, ServiceInterface } from '@standardnotes/services'
|
||||
|
||||
export interface AbstractUIServiceInterface<EventName = string, EventData = unknown>
|
||||
extends ServiceInterface<EventName, EventData> {
|
||||
onAppStart(): Promise<void>
|
||||
onAppEvent(event: ApplicationEvent): Promise<void>
|
||||
}
|
||||
@@ -4,6 +4,30 @@ import { SKAlert } from '@standardnotes/styles'
|
||||
import { alertDialog, confirmDialog } from './Functions'
|
||||
|
||||
export class WebAlertService extends AlertService {
|
||||
override confirmV2(dto: {
|
||||
text: string
|
||||
title?: string | undefined
|
||||
confirmButtonText?: string | undefined
|
||||
confirmButtonType?: ButtonType | undefined
|
||||
cancelButtonText?: string | undefined
|
||||
}): Promise<boolean> {
|
||||
return confirmDialog({
|
||||
text: dto.text,
|
||||
title: dto.title,
|
||||
confirmButtonText: dto.confirmButtonText,
|
||||
cancelButtonText: dto.cancelButtonText,
|
||||
confirmButtonStyle: dto.confirmButtonType === ButtonType.Danger ? 'danger' : 'info',
|
||||
})
|
||||
}
|
||||
|
||||
override alertV2(dto: {
|
||||
text: string
|
||||
title?: string | undefined
|
||||
closeButtonText?: string | undefined
|
||||
}): Promise<void> {
|
||||
return alertDialog({ text: dto.text, title: dto.title, closeButtonText: dto.closeButtonText })
|
||||
}
|
||||
|
||||
alert(text: string, title?: string, closeButtonText?: string) {
|
||||
return alertDialog({ text, title, closeButtonText })
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WebApplicationInterface } from './../../WebApplication/WebApplicationInterface'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { AegisToAuthenticatorConverter } from './AegisToAuthenticatorConverter'
|
||||
import data from './testData'
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
|
||||
type AegisData = {
|
||||
db: {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
*/
|
||||
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { DecryptedTransferPayload, NoteContent, TagContent } from '@standardnotes/models'
|
||||
import { EvernoteConverter } from './EvernoteConverter'
|
||||
import data from './testData'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
|
||||
// Mock dayjs so dayjs.extend() doesn't throw an error in EvernoteConverter.ts
|
||||
jest.mock('dayjs', () => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { DecryptedTransferPayload, NoteContent, TagContent } from '@standardnotes/models'
|
||||
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'
|
||||
dayjs.extend(customParseFormat)
|
||||
dayjs.extend(utc)
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { WebApplicationInterface } from '@standardnotes/snjs'
|
||||
import { jsonTestData, htmlTestData } from './testData'
|
||||
import { GoogleKeepConverter } from './GoogleKeepConverter'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
|
||||
describe('GoogleKeepConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
|
||||
type GoogleKeepJsonNote = {
|
||||
color: string
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { parseFileName } from '@standardnotes/filepicker'
|
||||
import { FeatureStatus, WebApplicationInterface } from '@standardnotes/services'
|
||||
import { FeatureStatus } from '@standardnotes/services'
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
import { AegisToAuthenticatorConverter } from './AegisConverter/AegisToAuthenticatorConverter'
|
||||
import { EvernoteConverter } from './EvernoteConverter/EvernoteConverter'
|
||||
@@ -8,6 +8,7 @@ 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'
|
||||
|
||||
@@ -82,7 +83,7 @@ export class Importer {
|
||||
const insertedItems = await Promise.all(
|
||||
payloads.map(async (payload) => {
|
||||
const content = payload.content as NoteContent
|
||||
const note = this.application.mutator.createTemplateItem(
|
||||
const note = this.application.items.createTemplateItem(
|
||||
payload.content_type,
|
||||
{
|
||||
text: content.text,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { parseFileName } from '@standardnotes/filepicker'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
|
||||
export class PlaintextConverter {
|
||||
constructor(protected application: WebApplicationInterface) {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
import { SimplenoteConverter } from './SimplenoteConverter'
|
||||
import data from './testData'
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { WebApplicationInterface } from '../../WebApplication/WebApplicationInterface'
|
||||
|
||||
type SimplenoteItem = {
|
||||
creationDate: string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Environment, Platform } from '@standardnotes/snjs'
|
||||
import { Environment, Platform } from '@standardnotes/models'
|
||||
import { isMacPlatform } from './platformCheck'
|
||||
import {
|
||||
CREATE_NEW_NOTE_KEYBOARD_COMMAND,
|
||||
|
||||
@@ -2,6 +2,7 @@ const PREFERENCE_IDS = [
|
||||
'general',
|
||||
'account',
|
||||
'security',
|
||||
'vaults',
|
||||
'appearance',
|
||||
'backups',
|
||||
'listed',
|
||||
|
||||
@@ -8,41 +8,31 @@ import {
|
||||
SNTheme,
|
||||
} from '@standardnotes/models'
|
||||
import { removeFromArray } from '@standardnotes/utils'
|
||||
import {
|
||||
AbstractService,
|
||||
WebApplicationInterface,
|
||||
InternalEventBusInterface,
|
||||
ApplicationEvent,
|
||||
StorageValueModes,
|
||||
FeatureStatus,
|
||||
} from '@standardnotes/services'
|
||||
import { InternalEventBusInterface, ApplicationEvent, StorageValueModes, FeatureStatus } from '@standardnotes/services'
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '../WebApplication/WebApplicationInterface'
|
||||
import { AbstractUIServicee } from '../Abstract/AbstractUIService'
|
||||
|
||||
const CachedThemesKey = 'cachedThemes'
|
||||
const TimeBeforeApplyingColorScheme = 5
|
||||
const DefaultThemeIdentifier = 'Default'
|
||||
|
||||
export class ThemeManager extends AbstractService {
|
||||
export class ThemeManager extends AbstractUIServicee {
|
||||
private activeThemes: string[] = []
|
||||
private unregisterDesktop?: () => void
|
||||
private unregisterStream!: () => void
|
||||
private lastUseDeviceThemeSettings = false
|
||||
private unsubApp!: () => void
|
||||
|
||||
constructor(
|
||||
protected application: WebApplicationInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
this.addAppEventObserverAfterSubclassesFinishConstructing()
|
||||
constructor(application: WebApplicationInterface, internalEventBus: InternalEventBusInterface) {
|
||||
super(application, internalEventBus)
|
||||
this.colorSchemeEventHandler = this.colorSchemeEventHandler.bind(this)
|
||||
}
|
||||
|
||||
async onAppStart() {
|
||||
override async onAppStart() {
|
||||
this.registerObservers()
|
||||
}
|
||||
|
||||
async onAppEvent(event: ApplicationEvent) {
|
||||
override async onAppEvent(event: ApplicationEvent) {
|
||||
switch (event) {
|
||||
case ApplicationEvent.SignedOut: {
|
||||
this.deactivateAllThemes()
|
||||
@@ -76,25 +66,6 @@ export class ThemeManager extends AbstractService {
|
||||
}
|
||||
}
|
||||
|
||||
addAppEventObserverAfterSubclassesFinishConstructing() {
|
||||
setTimeout(() => {
|
||||
this.addAppEventObserver()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
addAppEventObserver() {
|
||||
if (this.application.isStarted()) {
|
||||
void this.onAppStart()
|
||||
}
|
||||
|
||||
this.unsubApp = this.application.addEventObserver(async (event: ApplicationEvent) => {
|
||||
await this.onAppEvent(event)
|
||||
if (event === ApplicationEvent.Started) {
|
||||
void this.onAppStart()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async handleMobileColorSchemeChangeEvent() {
|
||||
const useDeviceThemeSettings = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
|
||||
|
||||
@@ -124,10 +95,6 @@ export class ThemeManager extends AbstractService {
|
||||
}
|
||||
}
|
||||
|
||||
get webApplication() {
|
||||
return this.application as WebApplicationInterface
|
||||
}
|
||||
|
||||
override deinit() {
|
||||
this.activeThemes.length = 0
|
||||
|
||||
@@ -143,11 +110,6 @@ export class ThemeManager extends AbstractService {
|
||||
mq.removeListener(this.colorSchemeEventHandler)
|
||||
}
|
||||
|
||||
;(this.application as unknown) = undefined
|
||||
|
||||
this.unsubApp()
|
||||
;(this.unsubApp as unknown) = undefined
|
||||
|
||||
super.deinit()
|
||||
}
|
||||
|
||||
@@ -166,7 +128,7 @@ export class ThemeManager extends AbstractService {
|
||||
const status = this.application.features.getFeatureStatus(theme.identifier)
|
||||
if (status !== FeatureStatus.Entitled) {
|
||||
if (theme.active) {
|
||||
this.application.mutator.toggleTheme(theme).catch(console.error)
|
||||
this.application.componentManager.toggleTheme(theme.uuid).catch(console.error)
|
||||
} else {
|
||||
this.deactivateTheme(theme.uuid)
|
||||
}
|
||||
@@ -242,7 +204,7 @@ export class ThemeManager extends AbstractService {
|
||||
|
||||
const toggleActiveTheme = () => {
|
||||
if (activeTheme) {
|
||||
void this.application.mutator.toggleTheme(activeTheme)
|
||||
void this.application.componentManager.toggleTheme(activeTheme.uuid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +214,7 @@ export class ThemeManager extends AbstractService {
|
||||
} else {
|
||||
const theme = themes.find((theme) => theme.package_info.identifier === themeIdentifier)
|
||||
if (theme && !theme.active) {
|
||||
this.application.mutator.toggleTheme(theme).catch(console.error)
|
||||
this.application.componentManager.toggleTheme(theme.uuid).catch(console.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,7 +234,7 @@ export class ThemeManager extends AbstractService {
|
||||
}
|
||||
|
||||
private registerObservers() {
|
||||
this.unregisterDesktop = this.webApplication.getDesktopService()?.registerUpdateObserver((component) => {
|
||||
this.unregisterDesktop = this.application.getDesktopService()?.registerUpdateObserver((component) => {
|
||||
if (component.active && component.isTheme()) {
|
||||
this.deactivateTheme(component.uuid)
|
||||
setTimeout(() => {
|
||||
|
||||
216
packages/ui-services/src/Vaults/VaultDisplayService.ts
Normal file
216
packages/ui-services/src/Vaults/VaultDisplayService.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import {
|
||||
ApplicationEvent,
|
||||
ApplicationStage,
|
||||
ApplicationStageChangedEventPayload,
|
||||
Challenge,
|
||||
ChallengePrompt,
|
||||
ChallengeReason,
|
||||
ChallengeStrings,
|
||||
ChallengeValidation,
|
||||
InternalEventBusInterface,
|
||||
InternalEventHandlerInterface,
|
||||
InternalEventInterface,
|
||||
StorageKey,
|
||||
VaultServiceEvent,
|
||||
} from '@standardnotes/services'
|
||||
import { VaultDisplayOptions, VaultDisplayOptionsPersistable, VaultListingInterface } from '@standardnotes/models'
|
||||
import { VaultDisplayServiceEvent } from './VaultDisplayServiceEvent'
|
||||
import { AbstractUIServicee } from '../Abstract/AbstractUIService'
|
||||
import { WebApplicationInterface } from '../WebApplication/WebApplicationInterface'
|
||||
import { VaultDisplayServiceInterface } from './VaultDisplayServiceInterface'
|
||||
import { action, makeObservable, observable } from 'mobx'
|
||||
|
||||
export class VaultDisplayService
|
||||
extends AbstractUIServicee<VaultDisplayServiceEvent>
|
||||
implements VaultDisplayServiceInterface, InternalEventHandlerInterface
|
||||
{
|
||||
options: VaultDisplayOptions
|
||||
|
||||
public exclusivelyShownVault: VaultListingInterface | undefined = undefined
|
||||
|
||||
constructor(application: WebApplicationInterface, internalEventBus: InternalEventBusInterface) {
|
||||
super(application, internalEventBus)
|
||||
|
||||
this.options = new VaultDisplayOptions({ exclude: [], locked: [] })
|
||||
|
||||
internalEventBus.addEventHandler(this, VaultServiceEvent.VaultLocked)
|
||||
internalEventBus.addEventHandler(this, VaultServiceEvent.VaultUnlocked)
|
||||
internalEventBus.addEventHandler(this, ApplicationEvent.ApplicationStageChanged)
|
||||
|
||||
makeObservable(this, {
|
||||
options: observable,
|
||||
|
||||
isVaultExplicitelyExcluded: observable,
|
||||
isVaultExclusivelyShown: observable,
|
||||
exclusivelyShownVault: observable,
|
||||
|
||||
hideVault: action,
|
||||
unhideVault: action,
|
||||
showOnlyVault: action,
|
||||
})
|
||||
}
|
||||
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === VaultServiceEvent.VaultLocked || event.type === VaultServiceEvent.VaultUnlocked) {
|
||||
this.handleVaultLockingStatusChanged()
|
||||
} else if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
if (stage === ApplicationStage.StorageDecrypted_09) {
|
||||
void this.loadVaultSelectionOptionsFromDisk()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleVaultLockingStatusChanged(): void {
|
||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
||||
|
||||
const options = this.options.newOptionsByIntakingLockedVaults(lockedVaults)
|
||||
this.setVaultSelectionOptions(options)
|
||||
}
|
||||
|
||||
public getOptions(): VaultDisplayOptions {
|
||||
return this.options
|
||||
}
|
||||
|
||||
isVaultExplicitelyExcluded = (vault: VaultListingInterface): boolean => {
|
||||
return this.options.isVaultExplicitelyExcluded(vault) ?? false
|
||||
}
|
||||
|
||||
isVaultDisabledOrLocked(vault: VaultListingInterface): boolean {
|
||||
return this.options.isVaultDisabledOrLocked(vault)
|
||||
}
|
||||
|
||||
isVaultExclusivelyShown = (vault: VaultListingInterface): boolean => {
|
||||
return this.options.isVaultExclusivelyShown(vault)
|
||||
}
|
||||
|
||||
isInExclusiveDisplayMode(): boolean {
|
||||
return this.options.isInExclusiveDisplayMode()
|
||||
}
|
||||
|
||||
changeToMultipleVaultDisplayMode(): void {
|
||||
const vaults = this.application.vaults.getVaults()
|
||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
||||
|
||||
const newOptions = new VaultDisplayOptions({
|
||||
exclude: vaults
|
||||
.map((vault) => vault.systemIdentifier)
|
||||
.filter((identifier) => identifier !== this.exclusivelyShownVault?.systemIdentifier),
|
||||
locked: lockedVaults.map((vault) => vault.systemIdentifier),
|
||||
})
|
||||
|
||||
this.setVaultSelectionOptions(newOptions)
|
||||
}
|
||||
|
||||
hideVault = (vault: VaultListingInterface) => {
|
||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
||||
const newOptions = this.options.newOptionsByExcludingVault(vault, lockedVaults)
|
||||
this.setVaultSelectionOptions(newOptions)
|
||||
}
|
||||
|
||||
unhideVault = async (vault: VaultListingInterface) => {
|
||||
if (this.application.vaults.isVaultLocked(vault)) {
|
||||
const unlocked = await this.unlockVault(vault)
|
||||
if (!unlocked) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
||||
const newOptions = this.options.newOptionsByUnexcludingVault(vault, lockedVaults)
|
||||
this.setVaultSelectionOptions(newOptions)
|
||||
}
|
||||
|
||||
showOnlyVault = async (vault: VaultListingInterface) => {
|
||||
if (this.application.vaults.isVaultLocked(vault)) {
|
||||
const unlocked = await this.unlockVault(vault)
|
||||
if (!unlocked) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const newOptions = new VaultDisplayOptions({ exclusive: vault.systemIdentifier })
|
||||
this.setVaultSelectionOptions(newOptions)
|
||||
}
|
||||
|
||||
async unlockVault(vault: VaultListingInterface): Promise<boolean> {
|
||||
if (!this.application.vaults.isVaultLocked(vault)) {
|
||||
throw new Error('Attempting to unlock a vault that is not locked.')
|
||||
}
|
||||
|
||||
const challenge = new Challenge(
|
||||
[new ChallengePrompt(ChallengeValidation.None, undefined, 'Password')],
|
||||
ChallengeReason.Custom,
|
||||
true,
|
||||
ChallengeStrings.UnlockVault(vault.name),
|
||||
ChallengeStrings.EnterVaultPassword,
|
||||
)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.application.challenges.addChallengeObserver(challenge, {
|
||||
onCancel() {
|
||||
resolve(false)
|
||||
},
|
||||
onNonvalidatedSubmit: async (challengeResponse) => {
|
||||
const value = challengeResponse.getDefaultValue()
|
||||
if (!value) {
|
||||
this.application.challenges.completeChallenge(challenge)
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
|
||||
const password = value.value as string
|
||||
|
||||
const unlocked = await this.application.vaults.unlockNonPersistentVault(vault, password)
|
||||
if (!unlocked) {
|
||||
this.application.challenges.setValidationStatusForChallenge(challenge, value, false)
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
|
||||
this.application.challenges.completeChallenge(challenge)
|
||||
resolve(true)
|
||||
},
|
||||
})
|
||||
|
||||
void this.application.challenges.promptForChallengeResponse(challenge)
|
||||
})
|
||||
}
|
||||
|
||||
private setVaultSelectionOptions = (options: VaultDisplayOptions) => {
|
||||
this.options = options
|
||||
|
||||
if (this.isInExclusiveDisplayMode()) {
|
||||
this.exclusivelyShownVault = this.application.vaults.getVault({
|
||||
keySystemIdentifier: this.options.getExclusivelyShownVault(),
|
||||
})
|
||||
} else {
|
||||
this.exclusivelyShownVault = undefined
|
||||
}
|
||||
|
||||
this.application.items.setVaultDisplayOptions(options)
|
||||
|
||||
void this.notifyEvent(VaultDisplayServiceEvent.VaultDisplayOptionsChanged, options)
|
||||
|
||||
if (this.application.isLaunched()) {
|
||||
this.application.setValue(StorageKey.VaultSelectionOptions, options.getPersistableValue())
|
||||
}
|
||||
}
|
||||
|
||||
private loadVaultSelectionOptionsFromDisk = (): void => {
|
||||
const raw = this.application.getValue<VaultDisplayOptionsPersistable>(StorageKey.VaultSelectionOptions)
|
||||
if (!raw) {
|
||||
return
|
||||
}
|
||||
|
||||
const options = VaultDisplayOptions.FromPersistableValue(raw)
|
||||
|
||||
this.options = options
|
||||
void this.notifyEvent(VaultDisplayServiceEvent.VaultDisplayOptionsChanged, options)
|
||||
}
|
||||
|
||||
override deinit(): void {
|
||||
;(this.options as unknown) = undefined
|
||||
super.deinit()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum VaultDisplayServiceEvent {
|
||||
VaultDisplayOptionsChanged = 'VaultDisplayOptionsChanged',
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { VaultDisplayOptions, VaultListingInterface } from '@standardnotes/models'
|
||||
import { AbstractUIServiceInterface } from '../Abstract/AbstractUIServiceInterface'
|
||||
|
||||
export interface VaultDisplayServiceInterface extends AbstractUIServiceInterface {
|
||||
exclusivelyShownVault?: VaultListingInterface
|
||||
|
||||
getOptions(): VaultDisplayOptions
|
||||
|
||||
isVaultDisabledOrLocked(vault: VaultListingInterface): boolean
|
||||
isVaultExplicitelyExcluded: (vault: VaultListingInterface) => boolean
|
||||
isVaultExclusivelyShown: (vault: VaultListingInterface) => boolean
|
||||
isInExclusiveDisplayMode(): boolean
|
||||
|
||||
changeToMultipleVaultDisplayMode(): void
|
||||
|
||||
hideVault: (vault: VaultListingInterface) => void
|
||||
unhideVault: (vault: VaultListingInterface) => void
|
||||
showOnlyVault: (vault: VaultListingInterface) => void
|
||||
unlockVault(vault: VaultListingInterface): Promise<boolean>
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
ApplicationInterface,
|
||||
DesktopManagerInterface,
|
||||
MobileDeviceInterface,
|
||||
WebAppEvent,
|
||||
} from '@standardnotes/services'
|
||||
|
||||
export interface WebApplicationInterface extends ApplicationInterface {
|
||||
notifyWebEvent(event: WebAppEvent, data?: unknown): void
|
||||
getDesktopService(): DesktopManagerInterface | undefined
|
||||
handleMobileEnteringBackgroundEvent(): Promise<void>
|
||||
handleMobileGainingFocusEvent(): Promise<void>
|
||||
handleMobileLosingFocusEvent(): Promise<void>
|
||||
handleMobileResumingFromBackgroundEvent(): Promise<void>
|
||||
handleMobileColorSchemeChangeEvent(): void
|
||||
handleMobileKeyboardWillChangeFrameEvent(frame: { height: number; contentHeight: number }): void
|
||||
handleMobileKeyboardDidChangeFrameEvent(frame: { height: number; contentHeight: number }): void
|
||||
isNativeMobileWeb(): boolean
|
||||
mobileDevice(): MobileDeviceInterface
|
||||
handleAndroidBackButtonPressed(): void
|
||||
addAndroidBackHandlerEventListener(listener: () => boolean): (() => void) | undefined
|
||||
setAndroidBackHandlerFallbackListener(listener: () => boolean): void
|
||||
generateUUID(): string
|
||||
}
|
||||
@@ -33,3 +33,9 @@ export * from './Toast/ToastService'
|
||||
export * from './Toast/ToastServiceInterface'
|
||||
export * from './StatePersistence/StatePersistence'
|
||||
export * from './Import'
|
||||
|
||||
export * from './Vaults/VaultDisplayService'
|
||||
export * from './Vaults/VaultDisplayServiceEvent'
|
||||
export * from './Vaults/VaultDisplayServiceInterface'
|
||||
|
||||
export * from './WebApplication/WebApplicationInterface'
|
||||
|
||||
Reference in New Issue
Block a user