fix: don't wait until regaining focus to lock app

This commit is contained in:
Antonella Sgarlatta
2021-06-07 19:07:31 -03:00
parent 3d2b4e3521
commit 98c6078a0d
3 changed files with 20 additions and 56 deletions

View File

@@ -1,10 +1,8 @@
import { ApplicationService } from '@standardnotes/snjs'; import { ApplicationService } from '@standardnotes/snjs';
import { WebApplication } from '@/ui_models/application';
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import { AppStateEvent } from '@/ui_models/app_state';
const MILLISECONDS_PER_SECOND = 1000; const MILLISECONDS_PER_SECOND = 1000;
const FOCUS_POLL_INTERVAL = 1 * MILLISECONDS_PER_SECOND; const POLL_INTERVAL = 10;
const LOCK_INTERVAL_NONE = 0; const LOCK_INTERVAL_NONE = 0;
const LOCK_INTERVAL_IMMEDIATE = 1; const LOCK_INTERVAL_IMMEDIATE = 1;
const LOCK_INTERVAL_ONE_MINUTE = 60 * MILLISECONDS_PER_SECOND; const LOCK_INTERVAL_ONE_MINUTE = 60 * MILLISECONDS_PER_SECOND;
@@ -15,37 +13,21 @@ const STORAGE_KEY_AUTOLOCK_INTERVAL = "AutoLockIntervalKey";
export class AutolockService extends ApplicationService { export class AutolockService extends ApplicationService {
private unsubState?: () => void; private pollInterval: any
private pollFocusInterval: any
private lastFocusState?: 'hidden' | 'visible' private lastFocusState?: 'hidden' | 'visible'
private lockAfterDate?: Date private lockAfterDate?: Date
private lockTimeout?: any
onAppLaunch() { onAppLaunch() {
this.observeVisibility(); if (!isDesktopApplication()) {
this.beginPolling();
}
return super.onAppLaunch(); return super.onAppLaunch();
} }
observeVisibility() {
this.unsubState = (this.application as WebApplication).getAppState().addObserver(
async (eventName) => {
if (eventName === AppStateEvent.WindowDidBlur) {
this.documentVisibilityChanged(false);
} else if (eventName === AppStateEvent.WindowDidFocus) {
this.documentVisibilityChanged(true);
}
}
);
if (!isDesktopApplication()) {
this.beginWebFocusPolling();
}
}
deinit() { deinit() {
this.unsubState?.();
this.cancelAutoLockTimer(); this.cancelAutoLockTimer();
if (this.pollFocusInterval) { if (this.pollInterval) {
clearInterval(this.pollFocusInterval); clearInterval(this.pollInterval);
} }
} }
@@ -85,11 +67,15 @@ export class AutolockService extends ApplicationService {
* Verify document is in focus every so often as visibilitychange event is * Verify document is in focus every so often as visibilitychange event is
* not triggered on a typical window blur event but rather on tab changes. * not triggered on a typical window blur event but rather on tab changes.
*/ */
beginWebFocusPolling() { beginPolling() {
this.pollFocusInterval = setInterval(() => { this.pollInterval = setInterval(async () => {
if (document.hidden) { const locked = await this.application.isLocked();
/** Native event listeners will have fired */ if (
return; !locked &&
this.lockAfterDate &&
new Date() > this.lockAfterDate
) {
this.lockApplication();
} }
const hasFocus = document.hasFocus(); const hasFocus = document.hasFocus();
if (hasFocus && this.lastFocusState === 'hidden') { if (hasFocus && this.lastFocusState === 'hidden') {
@@ -99,7 +85,7 @@ export class AutolockService extends ApplicationService {
} }
/* Save this to compare against next time around */ /* Save this to compare against next time around */
this.lastFocusState = hasFocus ? 'visible' : 'hidden'; this.lastFocusState = hasFocus ? 'visible' : 'hidden';
}, FOCUS_POLL_INTERVAL); }, POLL_INTERVAL);
} }
getAutoLockIntervalOptions() { getAutoLockIntervalOptions() {
@@ -129,14 +115,6 @@ export class AutolockService extends ApplicationService {
async documentVisibilityChanged(visible: boolean) { async documentVisibilityChanged(visible: boolean) {
if (visible) { if (visible) {
const locked = await this.application.isLocked();
if (
!locked &&
this.lockAfterDate &&
new Date() > this.lockAfterDate
) {
this.lockApplication();
}
this.cancelAutoLockTimer(); this.cancelAutoLockTimer();
} else { } else {
this.beginAutoLockTimer(); this.beginAutoLockTimer();
@@ -148,29 +126,15 @@ export class AutolockService extends ApplicationService {
if (interval === LOCK_INTERVAL_NONE) { if (interval === LOCK_INTERVAL_NONE) {
return; return;
} }
/**
* Use a timeout if possible, but if the computer is put to sleep, timeouts won't
* work. Need to set a date as backup. this.lockAfterDate does not need to be
* persisted, as living in memory is sufficient. If memory is cleared, then the
* application will lock anyway.
*/
const addToNow = (seconds: number) => { const addToNow = (seconds: number) => {
const date = new Date(); const date = new Date();
date.setSeconds(date.getSeconds() + seconds); date.setSeconds(date.getSeconds() + seconds);
return date; return date;
}; };
this.lockAfterDate = addToNow(interval / MILLISECONDS_PER_SECOND); this.lockAfterDate = addToNow(interval / MILLISECONDS_PER_SECOND);
clearTimeout(this.lockTimeout);
this.lockTimeout = setTimeout(() => {
this.cancelAutoLockTimer();
this.lockApplication();
this.lockAfterDate = undefined;
}, interval);
} }
cancelAutoLockTimer() { cancelAutoLockTimer() {
clearTimeout(this.lockTimeout);
this.lockAfterDate = undefined; this.lockAfterDate = undefined;
this.lockTimeout = undefined;
} }
} }

View File

@@ -134,7 +134,7 @@ export class AppState {
this.noAccountWarning.reset(); this.noAccountWarning.reset();
} }
this.actionsMenu.reset(); this.actionsMenu.reset();
this.unsubApp(); this.unsubApp?.();
this.unsubApp = undefined; this.unsubApp = undefined;
this.observers.length = 0; this.observers.length = 0;
this.appEventObserverRemovers.forEach((remover) => remover()); this.appEventObserverRemovers.forEach((remover) => remover());

View File

@@ -40,8 +40,8 @@ export class PureViewCtrl<P = CtrlProps, S = CtrlState> {
} }
deinit(): void { deinit(): void {
this.unsubApp(); this.unsubApp?.();
this.unsubState(); this.unsubState?.();
for (const disposer of this.reactionDisposers) { for (const disposer of this.reactionDisposers) {
disposer(); disposer();
} }