Improve event handling + restarts

This commit is contained in:
Mo Bitar
2020-02-12 14:21:58 -06:00
parent 0fcfd98e5d
commit a364a9ec03
19 changed files with 1202 additions and 814 deletions

View File

@@ -1,4 +1,6 @@
import { ApplicationEvents } from 'snjs';
export class PureCtrl { export class PureCtrl {
/* @ngInject */
constructor( constructor(
$scope, $scope,
$timeout, $timeout,
@@ -14,13 +16,22 @@ export class PureCtrl {
this.application = application; this.application = application;
this.state = {}; this.state = {};
this.props = {}; this.props = {};
this.addAppStateObserver();
this.addAppEventObserver();
$scope.$on('$destroy', () => { $scope.$on('$destroy', () => {
this.unsubApp(); this.unsubApp();
this.unsubState(); this.unsubState();
}); });
} }
$onInit() {
this.addAppStateObserver();
this.addAppEventObserver();
}
/** @private */
async resetState() {
this.state = {};
await this.setState({});
}
async setState(state) { async setState(state) {
return new Promise((resolve) => { return new Promise((resolve) => {
@@ -45,12 +56,28 @@ export class PureCtrl {
} }
addAppEventObserver() { addAppEventObserver() {
this.unsubApp = this.application.addEventObserver((eventName) => { if (this.application.isStarted()) {
this.onApplicationEvent(eventName); this.onAppStart();
}
if (!this.appState.isLocked()) {
this.onAppUnlock();
}
this.unsubApp = this.application.addEventObserver(async (eventName) => {
this.onAppEvent(eventName);
if (eventName === ApplicationEvents.Started) {
await this.resetState();
await this.onAppStart();
} else if (eventName === ApplicationEvents.Unlocked) {
await this.onAppUnlock();
} else if (eventName === ApplicationEvents.CompletedSync) {
this.onAppSync();
} else if (eventName === ApplicationEvents.KeyStatusChange) {
this.onAppKeyChange();
}
}); });
} }
onApplicationEvent(eventName) { onAppEvent(eventName) {
/** Optional override */ /** Optional override */
} }
@@ -58,4 +85,19 @@ export class PureCtrl {
/** Optional override */ /** Optional override */
} }
async onAppStart() {
/** Optional override */
}
async onAppUnlock() {
/** Optional override */
}
async onAppKeyChange() {
/** Optional override */
}
onAppSync() {
/** Optional override */
}
} }

View File

@@ -81,18 +81,18 @@ class EditorCtrl extends PureCtrl {
onReady: () => this.reloadPreferences() onReady: () => this.reloadPreferences()
}; };
this.addSyncStatusObserver(); this.addSyncStatusObserver();
this.registerKeyboardShortcuts(); this.registerKeyboardShortcuts();
application.onUnlock(() => {
this.streamItems();
this.registerComponentHandler();
});
/** Used by .pug template */ /** Used by .pug template */
this.prefKeyMonospace = PrefKeys.EditorMonospaceEnabled; this.prefKeyMonospace = PrefKeys.EditorMonospaceEnabled;
this.prefKeySpellcheck = PrefKeys.EditorSpellcheck; this.prefKeySpellcheck = PrefKeys.EditorSpellcheck;
this.prefKeyMarginResizers = PrefKeys.EditorResizersEnabled; this.prefKeyMarginResizers = PrefKeys.EditorResizersEnabled;
} }
onAppUnlock() {
super.onAppUnlock();
this.streamItems();
this.registerComponentHandler();
}
/** @override */ /** @override */
onAppStateEvent(eventName, data) { onAppStateEvent(eventName, data) {
@@ -107,7 +107,7 @@ class EditorCtrl extends PureCtrl {
} }
/** @override */ /** @override */
onApplicationEvent(eventName) { onAppEvent(eventName) {
if (!this.state.note) { if (!this.state.note) {
return; return;
} }

View File

@@ -46,23 +46,24 @@ class FooterCtrl extends PureCtrl {
this.arbitraryStatusMessage = string; this.arbitraryStatusMessage = string;
}); });
}); });
}
application.onUnlock(() => { onAppUnlock() {
this.application.hasPasscode().then((value) => { super.onAppUnlock();
this.setState({ this.application.hasPasscode().then((value) => {
hasPasscode: value this.setState({
}); hasPasscode: value
}); });
this.godService.checkForSecurityUpdate().then((available) => {
this.securityUpdateAvailable = available;
});
this.user = this.application.getUser();
this.updateOfflineStatus();
this.findErrors();
this.streamItems();
this.registerComponentHandler();
}); });
this.godService.checkForSecurityUpdate().then((available) => {
this.securityUpdateAvailable = available;
});
this.user = this.application.getUser();
this.updateOfflineStatus();
this.findErrors();
this.streamItems();
this.registerComponentHandler();
} }
addRootScopeListeners() { addRootScopeListeners() {
@@ -109,7 +110,7 @@ class FooterCtrl extends PureCtrl {
} }
/** @override */ /** @override */
onApplicationEvent(eventName) { onAppEvent(eventName) {
if (eventName === ApplicationEvents.EnteredOutOfSync) { if (eventName === ApplicationEvents.EnteredOutOfSync) {
this.outOfSync = true; this.outOfSync = true;
} else if (eventName === ApplicationEvents.ExitedOutOfSync) { } else if (eventName === ApplicationEvents.ExitedOutOfSync) {

View File

@@ -17,6 +17,7 @@ class LockScreenCtrl extends PureCtrl {
} }
$onInit() { $onInit() {
super.$onInit();
this.puppet.focusInput = () => { this.puppet.focusInput = () => {
this.passcodeInput.focus(); this.passcodeInput.focus();
}; };

View File

@@ -76,10 +76,12 @@ class NotesCtrl extends PureCtrl {
angular.element(document).ready(() => { angular.element(document).ready(() => {
this.reloadPreferences(); this.reloadPreferences();
}); });
application.onUnlock(() => { }
this.streamNotesAndTags();
this.reloadPreferences(); onAppUnlock() {
}); super.onAppUnlock();
this.streamNotesAndTags();
this.reloadPreferences();
} }
/** @override */ /** @override */
@@ -97,7 +99,7 @@ class NotesCtrl extends PureCtrl {
} }
/** @override */ /** @override */
onApplicationEvent(eventName) { onAppEvent(eventName) {
if (eventName === ApplicationEvents.SignedIn) { if (eventName === ApplicationEvents.SignedIn) {
/** Delete dummy note if applicable */ /** Delete dummy note if applicable */
if (this.state.selectedNote && this.state.selectedNote.dummy) { if (this.state.selectedNote && this.state.selectedNote.dummy) {
@@ -430,10 +432,17 @@ class NotesCtrl extends PureCtrl {
}); });
} }
if (note.errorDecrypting) { if (note.errorDecrypting) {
flags.push({ if(note.waitingForKeys) {
text: "Missing Keys", flags.push({
class: 'danger' text: "Waiting For Keys",
}); class: 'info'
});
} else {
flags.push({
text: "Missing Keys",
class: 'danger'
});
}
} }
if (note.deleted) { if (note.deleted) {
flags.push({ flags.push({

View File

@@ -36,20 +36,27 @@ class RootCtrl extends PureCtrl {
this.statusManager = statusManager; this.statusManager = statusManager;
this.themeManager = themeManager; this.themeManager = themeManager;
this.platformString = getPlatformString(); this.platformString = getPlatformString();
this.state = { this.state = { appClass: '' };
ready: false,
appClass: ''
};
this.loadApplication(); this.loadApplication();
this.addDragDropHandlers(); this.addDragDropHandlers();
application.onUnlock(() => {
this.handleAutoSignInFromParams();
});
this.lockScreenPuppet = { this.lockScreenPuppet = {
focusInput: () => { } focusInput: () => { }
}; };
} }
onAppStart() {
super.onAppStart();
this.setState({ ready: false });
}
onAppUnlock() {
super.onAppUnlock();
this.setState({ ready: true, needsUnlock: false });
this.application.componentManager.setDesktopManager(this.desktopManager);
this.application.registerService(this.themeManager);
this.handleAutoSignInFromParams();
}
async watchLockscreenValue() { async watchLockscreenValue() {
return new Promise((resolve) => { return new Promise((resolve) => {
const onLockscreenValue = (value) => { const onLockscreenValue = (value) => {
@@ -86,24 +93,12 @@ class RootCtrl extends PureCtrl {
} }
}); });
await this.application.launch(); await this.application.launch();
this.setState({ ready: true });
// this.addSyncStatusObserver();
// this.addSyncEventHandler();
} }
onUpdateAvailable() { onUpdateAvailable() {
this.$rootScope.$broadcast('new-update-available'); this.$rootScope.$broadcast('new-update-available');
}; };
/** @override */
async onApplicationEvent(eventName) {
if (eventName === ApplicationEvents.ApplicationUnlocked) {
this.setState({ needsUnlock: false });
this.application.componentManager.setDesktopManager(this.desktopManager);
this.application.registerService(this.themeManager);
}
}
/** @override */ /** @override */
async onAppStateEvent(eventName, data) { async onAppStateEvent(eventName, data) {
if (eventName === AppStateEvents.PanelResized) { if (eventName === AppStateEvents.PanelResized) {
@@ -118,7 +113,7 @@ class RootCtrl extends PureCtrl {
if (this.tagsCollapsed) { appClass += " collapsed-tags"; } if (this.tagsCollapsed) { appClass += " collapsed-tags"; }
this.setState({ appClass }); this.setState({ appClass });
} else if (eventName === AppStateEvents.WindowDidFocus) { } else if (eventName === AppStateEvents.WindowDidFocus) {
if (!(await this.application.isPasscodeLocked())) { if (!(await this.application.isLocked())) {
this.application.sync(); this.application.sync();
} }
} }

View File

@@ -23,28 +23,31 @@ class TagsPanelCtrl extends PureCtrl {
onReady: () => this.loadPreferences() onReady: () => this.loadPreferences()
}; };
this.state = { this.state = {
tags: [],
smartTags: [], smartTags: [],
noteCounts: {} noteCounts: {},
}; };
} }
onAppStart() {
super.onAppStart();
this.registerComponentHandler();
}
$onInit() { onAppUnlock() {
this.application.onStart(() => { super.onAppUnlock();
this.registerComponentHandler(); this.loadPreferences();
}); this.beginStreamingItems();
this.application.onUnlock(() => { const smartTags = this.application.getSmartTags();
this.loadPreferences(); this.setState({
this.beginStreamingItems(); smartTags: smartTags,
const smartTags = this.application.getSmartTags();
this.setState({
smartTags: smartTags,
});
this.selectTag(smartTags[0]);
}); });
this.selectTag(smartTags[0]);
}
this.application.onSync(() => { onAppSync() {
this.reloadNoteCounts(); super.onAppSync();
}); this.reloadNoteCounts();
} }
beginStreamingItems() { beginStreamingItems() {
@@ -58,10 +61,10 @@ class TagsPanelCtrl extends PureCtrl {
this.reloadNoteCounts(); this.reloadNoteCounts();
if (this.state.selectedTag) { if (this.state.selectedTag) {
/** If the selected tag has been deleted, revert to All view. */ /** If the selected tag has been deleted, revert to All view. */
const selectedTag = items.find((tag) => { const matchingTag = items.find((tag) => {
return tag.uuid === this.state.selectedTag.uuid; return tag.uuid === this.state.selectedTag.uuid;
}); });
if (selectedTag && selectedTag.deleted) { if (!matchingTag || matchingTag.deleted) {
this.selectTag(this.state.smartTags[0]); this.selectTag(this.state.smartTags[0]);
} }
} }

View File

@@ -2,11 +2,9 @@ import { isDesktopApplication, isNullOrUndefined } from '@/utils';
import template from '%/directives/account-menu.pug'; import template from '%/directives/account-menu.pug';
import { ProtectedActions } from 'snjs'; import { ProtectedActions } from 'snjs';
import { PureCtrl } from '@Controllers'; import { PureCtrl } from '@Controllers';
import { AppStateEvents } from '@/state';
import { import {
STRING_ACCOUNT_MENU_UNCHECK_MERGE, STRING_ACCOUNT_MENU_UNCHECK_MERGE,
STRING_SIGN_OUT_CONFIRMATION, STRING_SIGN_OUT_CONFIRMATION,
STRING_ERROR_DECRYPTING_IMPORT,
STRING_E2E_ENABLED, STRING_E2E_ENABLED,
STRING_LOCAL_ENC_ENABLED, STRING_LOCAL_ENC_ENABLED,
STRING_ENC_NOT_ENABLED, STRING_ENC_NOT_ENABLED,
@@ -51,6 +49,7 @@ class AccountMenuCtrl extends PureCtrl {
this.state = { this.state = {
appVersion: 'v' + (window.electronAppVersion || appVersion), appVersion: 'v' + (window.electronAppVersion || appVersion),
passcodeAutoLockOptions: this.lockManager.getAutoLockIntervalOptions(), passcodeAutoLockOptions: this.lockManager.getAutoLockIntervalOptions(),
user: this.application.getUser(),
formData: { formData: {
mergeLocal: true, mergeLocal: true,
ephemeral: false, ephemeral: false,
@@ -59,18 +58,22 @@ class AccountMenuCtrl extends PureCtrl {
}, },
mutable: {} mutable: {}
}; };
application.onUnlock(async () => {
this.setState(await this.refreshedCredentialState());
this.loadHost();
this.checkForSecurityUpdate();
this.reloadAutoLockInterval();
this.loadBackupsAvailability();
});
application.onCredentialChange(async () => {
this.setState(await this.refreshedCredentialState());
});
this.syncStatus = this.application.getSyncStatus(); this.syncStatus = this.application.getSyncStatus();
} }
async onAppKeyChange() {
super.onAppKeyChange();
this.setState(await this.refreshedCredentialState());
}
async onAppUnlock() {
super.onAppUnlock();
this.setState(await this.refreshedCredentialState());
this.loadHost();
this.checkForSecurityUpdate();
this.reloadAutoLockInterval();
this.loadBackupsAvailability();
}
async refreshedCredentialState() { async refreshedCredentialState() {
return { return {
@@ -81,6 +84,7 @@ class AccountMenuCtrl extends PureCtrl {
} }
$onInit() { $onInit() {
super.$onInit();
this.initProps({ this.initProps({
closeFunction: this.closeFunction closeFunction: this.closeFunction
}); });
@@ -88,7 +92,6 @@ class AccountMenuCtrl extends PureCtrl {
close() { close() {
this.$timeout(() => { this.$timeout(() => {
console.log(" : AccountMenuCtrl -> close -> timeout");
this.props.closeFunction()(); this.props.closeFunction()();
}); });
} }

View File

@@ -15,6 +15,7 @@ class ActionsMenuCtrl extends PureCtrl {
} }
$onInit() { $onInit() {
super.$onInit();
this.initProps({ this.initProps({
item: this.item item: this.item
}); });

View File

@@ -17,6 +17,7 @@ class EditorMenuCtrl extends PureCtrl {
} }
$onInit() { $onInit() {
super.$onInit();
const editors = this.application.componentManager.componentsForArea('editor-editor') const editors = this.application.componentManager.componentsForArea('editor-editor')
.sort((a, b) => { .sort((a, b) => {
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1; return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;

View File

@@ -1,21 +1,24 @@
import template from '%/directives/privileges-management-modal.pug'; import template from '%/directives/privileges-management-modal.pug';
import { PrivilegeCredentials } from 'snjs'; import { PrivilegeCredentials } from 'snjs';
import { PureCtrl } from '@Controllers';
class PrivilegesManagementModalCtrl { class PrivilegesManagementModalCtrl extends PureCtrl {
/* @ngInject */ /* @ngInject */
constructor( constructor(
$timeout, $timeout,
$element, $element,
application application
) { ) {
super(null, $timeout);
this.$element = $element; this.$element = $element;
this.$timeout = $timeout;
this.application = application; this.application = application;
application.onUnlock(() => { }
this.hasPasscode = application.hasPasscode();
this.hasAccount = !application.noAccount(); onAppUnlock() {
this.reloadPrivileges(); super.onAppUnlock();
}); this.hasPasscode = this.application.hasPasscode();
this.hasAccount = !this.application.noAccount();
this.reloadPrivileges();
} }
displayInfoForCredential(credential) { displayInfoForCredential(credential) {

View File

@@ -92,7 +92,7 @@ export class LockManager {
async documentVisibilityChanged(visible) { async documentVisibilityChanged(visible) {
if(visible) { if(visible) {
const locked = await this.application.isPasscodeLocked(); const locked = await this.application.isLocked();
if( if(
!locked && !locked &&
this.lockAfterDate && this.lockAfterDate &&

View File

@@ -1,25 +1,31 @@
import { isDesktopApplication, dictToArray } from '@/utils'; import { isDesktopApplication, dictToArray } from '@/utils';
import { SFPredicate, ContentTypes, CreateMaxPayloadFromAnyObject } from 'snjs'; import {
ApplicationEvents,
SFPredicate,
ContentTypes,
CreateMaxPayloadFromAnyObject
} from 'snjs';
const STREAM_ITEMS_PERMISSION = 'stream-items'; const STREAM_ITEMS_PERMISSION = 'stream-items';
/** A class for handling installation of system extensions */ /** A class for handling installation of system extensions */
export class NativeExtManager { export class NativeExtManager {
/* @ngInject */ /* @ngInject */
constructor(application, appState) { constructor(application) {
this.application = application; this.application = application;
this.extManagerId = 'org.standardnotes.extensions-manager'; this.extManagerId = 'org.standardnotes.extensions-manager';
this.batchManagerId = 'org.standardnotes.batch-manager'; this.batchManagerId = 'org.standardnotes.batch-manager';
application.onUnlock(() => {
this.unsub = application.addSingleEventObserver(ApplicationEvents.Unlocked, () => {
this.reload(); this.reload();
this.streamChanges(); this.streamChanges();
}); });
} }
isSystemExtension(extension) { isSystemExtension(extension) {
return this.nativeExtIds.includes(extension.uuid); return this.nativeExtIds.includes(extension.uuid);
} }
streamChanges() { streamChanges() {
this.application.streamItems({ this.application.streamItems({
contentType: ContentTypes.Component, contentType: ContentTypes.Component,
@@ -28,7 +34,7 @@ export class NativeExtManager {
} }
}); });
} }
reload() { reload() {
this.nativeExtIds = []; this.nativeExtIds = [];
// this.resolveExtensionsManager(); // this.resolveExtensionsManager();
@@ -53,12 +59,12 @@ export class NativeExtManager {
{ {
name: STREAM_ITEMS_PERMISSION, name: STREAM_ITEMS_PERMISSION,
content_types: [ content_types: [
ContentTypes.Component, ContentTypes.Component,
ContentTypes.Theme, ContentTypes.Theme,
ContentTypes.ServerExtension, ContentTypes.ServerExtension,
ContentTypes.ActionsExtension, ContentTypes.ActionsExtension,
ContentTypes.Mfa, ContentTypes.Mfa,
ContentTypes.Editor, ContentTypes.Editor,
ContentTypes.ExtensionRepo ContentTypes.ExtensionRepo
] ]
} }

View File

@@ -1,4 +1,4 @@
import { SFPredicate, ContentTypes, CreateMaxPayloadFromAnyObject } from 'snjs'; import { ApplicationEvents, SFPredicate, ContentTypes, CreateMaxPayloadFromAnyObject } from 'snjs';
export const PrefKeys = { export const PrefKeys = {
TagsPanelWidth: 'tagsPanelWidth', TagsPanelWidth: 'tagsPanelWidth',
@@ -24,8 +24,8 @@ export class PreferencesManager {
application application
) { ) {
this.application = application; this.application = application;
this.appState = appState; this.appState = appState;
application.onUnlock(() => { this.unsub = application.addSingleEventObserver(ApplicationEvents.Unlocked, () => {
this.streamPreferences(); this.streamPreferences();
this.loadSingleton(); this.loadSingleton();
}); });

View File

@@ -1,5 +1,5 @@
import _ from 'lodash'; import _ from 'lodash';
import { ContentTypes, StorageValueModes, EncryptionIntents, PureService } from 'snjs'; import { ApplicationEvents, ContentTypes, StorageValueModes, EncryptionIntents, PureService } from 'snjs';
import { AppStateEvents } from '@/state'; import { AppStateEvents } from '@/state';
const CACHED_THEMES_KEY = 'cachedThemes'; const CACHED_THEMES_KEY = 'cachedThemes';
@@ -16,12 +16,17 @@ export class ThemeManager extends PureService {
this.appState = appState; this.appState = appState;
this.desktopManager = desktopManager; this.desktopManager = desktopManager;
this.activeThemes = []; this.activeThemes = [];
this.registerObservers(); if (this.application.isStarted()) {
application.onStart(() => { this.onAppStart();
if (!desktopManager.isDesktop) { }
this.activateCachedThemes(); this.unsub = application.addEventObserver((event) => {
if (event === ApplicationEvents.Started) {
this.onAppStart();
} else if(event === ApplicationEvents.SignedOut) {
this.deactivateAllThemes();
} }
}); });
this.unsubState = appState.addObserver((eventName, data) => { this.unsubState = appState.addObserver((eventName, data) => {
if (eventName === AppStateEvents.DesktopExtsReady) { if (eventName === AppStateEvents.DesktopExtsReady) {
this.activateCachedThemes(); this.activateCachedThemes();
@@ -29,6 +34,13 @@ export class ThemeManager extends PureService {
}); });
} }
onAppStart() {
this.registerObservers();
if (!this.desktopManager.isDesktop) {
this.activateCachedThemes();
}
}
/** @override */ /** @override */
async deinit() { async deinit() {
super.deinit(); super.deinit();
@@ -72,8 +84,8 @@ export class ThemeManager extends PureService {
} }
deactivateAllThemes() { deactivateAllThemes() {
var activeThemes = this.application.componentManager.getActiveThemes(); const activeThemes = this.application.componentManager.getActiveThemes();
for (var theme of activeThemes) { for (const theme of activeThemes) {
if (theme) { if (theme) {
this.application.componentManager.deactivateComponent(theme); this.application.componentManager.deactivateComponent(theme);
} }
@@ -142,7 +154,7 @@ export class ThemeManager extends PureService {
); );
if (cachedThemes) { if (cachedThemes) {
const themes = []; const themes = [];
for(const cachedTheme of cachedThemes) { for (const cachedTheme of cachedThemes) {
const theme = await this.application.createItem({ const theme = await this.application.createItem({
contentType: ContentTypes.Theme, contentType: ContentTypes.Theme,
content: cachedTheme.content content: cachedTheme.content

View File

@@ -1,6 +1,6 @@
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import pull from 'lodash/pull'; import pull from 'lodash/pull';
import { ProtectedActions } from 'snjs'; import { ProtectedActions, ApplicationEvents } from 'snjs';
export const AppStateEvents = { export const AppStateEvents = {
TagChanged: 1, TagChanged: 1,
@@ -33,7 +33,23 @@ export class AppState {
this.application = application; this.application = application;
this.godService = godService; this.godService = godService;
this.observers = []; this.observers = [];
this.locked = true;
this.registerVisibilityObservers(); this.registerVisibilityObservers();
this.addAppEventObserver();
}
addAppEventObserver() {
this.unsubApp = this.application.addEventObserver(async (eventName) => {
if (eventName === ApplicationEvents.Started) {
this.locked = true;
} else if (eventName === ApplicationEvents.Unlocked) {
this.locked = false;
}
});
}
isLocked() {
return this.locked;
} }
registerVisibilityObservers() { registerVisibilityObservers() {
@@ -87,9 +103,9 @@ export class AppState {
this.selectedTag = tag; this.selectedTag = tag;
this.notifyEvent( this.notifyEvent(
AppStateEvents.TagChanged, AppStateEvents.TagChanged,
{ {
tag: tag, tag: tag,
previousTag: previousTag previousTag: previousTag
} }
); );
} }

View File

@@ -17,4 +17,4 @@
footer( footer(
ng-if='!self.state.needsUnlock' ng-if='!self.state.needsUnlock'
) )

1677
dist/javascripts/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long