refactor: improve device interface types (#996)

This commit is contained in:
Mo
2022-04-22 13:54:34 -05:00
committed by GitHub
parent 68ad0f17ae
commit abb85b3f11
22 changed files with 296 additions and 235 deletions

View File

@@ -1,37 +0,0 @@
/**
* This file will be imported by desktop, so we make sure imports are carrying
* as little extra code as possible with them.
*/
import { Environment } from '@standardnotes/snjs'
export interface ElectronDesktopCallbacks {
desktop_updateAvailable(): void
desktop_windowGainedFocus(): void
desktop_windowLostFocus(): void
desktop_onComponentInstallationComplete(componentData: any, error: any): Promise<void>
desktop_requestBackupFile(): Promise<string | undefined>
desktop_didBeginBackup(): void
desktop_didFinishBackup(success: boolean): void
}
/** Platform-specific (i-e Electron/browser) behavior is handled by a Bridge object. */
export interface Bridge {
readonly appVersion: string
environment: Environment
getKeychainValue(): Promise<unknown>
setKeychainValue(value: unknown): Promise<void>
clearKeychainValue(): Promise<void>
localBackupsCount(): Promise<number>
viewlocalBackups(): void
deleteLocalBackups(): Promise<void>
extensionsServerHost?: string
syncComponents(payloads: unknown[]): void
onMajorDataChange(): void
onInitialDataLoad(): void
onSignOut(): void
onSearch(text?: string): void
downloadBackup(): void | Promise<void>
}

View File

@@ -1,42 +0,0 @@
import { Bridge } from './Bridge'
import { Environment } from '@standardnotes/snjs'
const KEYCHAIN_STORAGE_KEY = 'keychain'
export class BrowserBridge implements Bridge {
constructor(public appVersion: string) {}
environment = Environment.Web
async getKeychainValue(): Promise<unknown> {
const value = localStorage.getItem(KEYCHAIN_STORAGE_KEY)
if (value) {
return JSON.parse(value)
}
return undefined
}
async setKeychainValue(value: unknown): Promise<void> {
localStorage.setItem(KEYCHAIN_STORAGE_KEY, JSON.stringify(value))
}
async clearKeychainValue(): Promise<void> {
localStorage.removeItem(KEYCHAIN_STORAGE_KEY)
}
async localBackupsCount(): Promise<number> {
/** Browsers cannot save backups, only let you download one */
return 0
}
/** No-ops */
/* eslint-disable @typescript-eslint/no-empty-function */
async deleteLocalBackups(): Promise<void> {}
viewlocalBackups(): void {}
syncComponents(): void {}
onMajorDataChange(): void {}
onInitialDataLoad(): void {}
onSearch(): void {}
downloadBackup(): void {}
onSignOut(): void {}
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable camelcase */
import {
SNComponent,
ComponentMutator,
@@ -8,27 +7,26 @@ import {
removeFromArray,
DesktopManagerInterface,
InternalEventBus,
DecryptedTransferPayload,
ComponentContent,
assert,
} from '@standardnotes/snjs'
import { WebAppEvent, WebApplication } from '@/UIModels/Application'
import { isDesktopApplication } from '@/Utils'
import { Bridge, ElectronDesktopCallbacks } from './Bridge'
import { DesktopDeviceInterface } from '../Device/DesktopDeviceInterface'
import { DesktopCommunicationReceiver } from '@/Device/DesktopWebCommunication'
/**
* An interface used by the Desktop application to interact with SN
*/
export class DesktopManager
extends ApplicationService
implements DesktopManagerInterface, ElectronDesktopCallbacks
implements DesktopManagerInterface, DesktopCommunicationReceiver
{
updateObservers: {
callback: (component: SNComponent) => void
}[] = []
isDesktop = isDesktopApplication()
dataLoaded = false
lastSearchedText?: string
constructor(application: WebApplication, private bridge: Bridge) {
constructor(application: WebApplication, private device: DesktopDeviceInterface) {
super(application, new InternalEventBus())
}
@@ -45,19 +43,20 @@ export class DesktopManager
super.onAppEvent(eventName).catch(console.error)
if (eventName === ApplicationEvent.LocalDataLoaded) {
this.dataLoaded = true
this.bridge.onInitialDataLoad()
this.device.onInitialDataLoad()
} else if (eventName === ApplicationEvent.MajorDataChange) {
this.bridge.onMajorDataChange()
this.device.onMajorDataChange()
}
}
saveBackup() {
this.bridge.onMajorDataChange()
this.device.onMajorDataChange()
}
getExtServerHost(): string {
console.assert(!!this.bridge.extensionsServerHost, 'extServerHost is null')
return this.bridge.extensionsServerHost as string
assert(this.device.extensionsServerHost)
return this.device.extensionsServerHost
}
/**
@@ -70,17 +69,13 @@ export class DesktopManager
// All `components` should be installed
syncComponentsInstallation(components: SNComponent[]) {
if (!this.isDesktop) {
return
}
Promise.all(
components.map((component) => {
return this.convertComponentForTransmission(component)
}),
)
.then((payloads) => {
this.bridge.syncComponents(payloads)
this.device.syncComponents(payloads)
})
.catch(console.error)
}
@@ -96,11 +91,8 @@ export class DesktopManager
}
searchText(text?: string) {
if (!this.isDesktop) {
return
}
this.lastSearchedText = text
this.bridge.onSearch(text)
this.device.onSearch(text)
}
redoSearch() {
@@ -109,23 +101,27 @@ export class DesktopManager
}
}
desktop_updateAvailable(): void {
updateAvailable(): void {
this.webApplication.notifyWebEvent(WebAppEvent.NewUpdateAvailable)
}
desktop_windowGainedFocus(): void {
windowGainedFocus(): void {
this.webApplication.notifyWebEvent(WebAppEvent.DesktopWindowGainedFocus)
}
desktop_windowLostFocus(): void {
windowLostFocus(): void {
this.webApplication.notifyWebEvent(WebAppEvent.DesktopWindowLostFocus)
}
async desktop_onComponentInstallationComplete(componentData: any, error: any) {
async onComponentInstallationComplete(
componentData: DecryptedTransferPayload<ComponentContent>,
error: unknown,
) {
const component = this.application.items.findItem(componentData.uuid)
if (!component) {
return
}
const updatedComponent = await this.application.mutator.changeAndSaveItem(
component,
(m) => {
@@ -133,7 +129,9 @@ export class DesktopManager
if (error) {
mutator.setAppDataItem(AppDataField.ComponentInstallError, error)
} else {
mutator.local_url = componentData.content.local_url
// eslint-disable-next-line camelcase
mutator.local_url = componentData.content.local_url as string
// eslint-disable-next-line camelcase
mutator.package_info = componentData.content.package_info
mutator.setAppDataItem(AppDataField.ComponentInstallError, undefined)
}
@@ -146,7 +144,7 @@ export class DesktopManager
}
}
async desktop_requestBackupFile(): Promise<string | undefined> {
async requestBackupFile(): Promise<string | undefined> {
const encrypted = this.application.hasProtectionSources()
const data = encrypted
? await this.application.createEncryptedBackupFileForAutomatedDesktopBackups()
@@ -159,11 +157,11 @@ export class DesktopManager
return undefined
}
desktop_didBeginBackup() {
didBeginBackup() {
this.webApplication.getAppState().beganBackupDownload()
}
desktop_didFinishBackup(success: boolean) {
didFinishBackup(success: boolean) {
this.webApplication.getAppState().endedBackupDownload(success)
}
}

View File

@@ -22,7 +22,7 @@ const DefaultThemeIdentifier = 'Default'
export class ThemeManager extends ApplicationService {
private activeThemes: UuidString[] = []
private unregisterDesktop!: () => void
private unregisterDesktop?: () => void
private unregisterStream!: () => void
private lastUseDeviceThemeSettings = false
@@ -91,10 +91,12 @@ export class ThemeManager extends ApplicationService {
override deinit() {
this.activeThemes.length = 0
this.unregisterDesktop()
this.unregisterDesktop?.()
this.unregisterStream()
;(this.unregisterDesktop as unknown) = undefined
;(this.unregisterStream as unknown) = undefined
window
.matchMedia('(prefers-color-scheme: dark)')
.removeEventListener('change', this.colorSchemeEventHandler)
@@ -212,7 +214,7 @@ export class ThemeManager extends ApplicationService {
private registerObservers() {
this.unregisterDesktop = this.webApplication
.getDesktopService()
.registerUpdateObserver((component) => {
?.registerUpdateObserver((component) => {
if (component.active && component.isTheme()) {
this.deactivateTheme(component.uuid)
setTimeout(() => {