Handle setTimeout called when tab is shown (#6257)

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Paulus Schoutsen 2020-06-29 14:29:05 -07:00 committed by GitHub
parent 7b0e743eca
commit 71faaf2ab1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 46 deletions

View File

@ -76,11 +76,15 @@ export class HomeAssistantAppEl extends HassElement {
// @ts-ignore
this._loadHassTranslations(this.hass!.language, "state");
this.addEventListener("unsuspend-app", () => this._onVisible(), false);
document.addEventListener(
"visibilitychange",
() => this._handleVisibilityChange(),
() => this._checkVisibility(),
false
);
document.addEventListener("freeze", () => this._suspendApp());
document.addEventListener("resume", () => this._checkVisibility());
}
protected hassReconnected() {
@ -148,30 +152,53 @@ export class HomeAssistantAppEl extends HassElement {
: route.path.substr(1, dividerPos - 1);
}
protected _handleVisibilityChange() {
protected _checkVisibility() {
if (document.hidden) {
// If the document is hidden, we will prevent reconnects until we are visible again
this.hass!.connection.suspendReconnectUntil(
new Promise((resolve) => {
this._visiblePromiseResolve = resolve;
})
);
// We close the connection to Home Assistant after being hidden for 5 minutes
this._hiddenTimeout = window.setTimeout(() => {
this._hiddenTimeout = undefined;
this.hass!.connection.suspend();
}, 300000);
this._onHidden();
} else {
// Clear timer to close the connection
if (this._hiddenTimeout) {
clearTimeout(this._hiddenTimeout);
this._hiddenTimeout = undefined;
}
// Unsuspend the reconnect
if (this._visiblePromiseResolve) {
this._visiblePromiseResolve();
this._visiblePromiseResolve = undefined;
this._onVisible();
}
}
private _onHidden() {
if (this._visiblePromiseResolve) {
return;
}
this.hass!.connection.suspendReconnectUntil(
new Promise((resolve) => {
this._visiblePromiseResolve = resolve;
})
);
// We close the connection to Home Assistant after being hidden for 5 minutes
this._hiddenTimeout = window.setTimeout(() => {
this._hiddenTimeout = undefined;
// setTimeout can be delayed in the background and only fire
// when we switch to the tab or app again (Hey Android!)
if (!document.hidden) {
this._suspendApp();
}
}, 300000);
window.addEventListener("focus", () => this._onVisible(), { once: true });
}
private _suspendApp() {
if (!this.hass!.connection.connected) {
return;
}
this.hass!.connection.suspend();
}
private _onVisible() {
// Clear timer to close the connection
if (this._hiddenTimeout) {
clearTimeout(this._hiddenTimeout);
this._hiddenTimeout = undefined;
}
// Unsuspend the reconnect
if (this._visiblePromiseResolve) {
this._visiblePromiseResolve();
this._visiblePromiseResolve = undefined;
}
}
}

View File

@ -99,11 +99,13 @@ class PartialPanelResolver extends HassRouterPage {
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
// Attach listeners for visibility
document.addEventListener(
"visibilitychange",
() => this._handleVisibilityChange(),
() => this._checkVisibility(),
false
);
document.addEventListener("resume", () => this._checkVisibility());
}
protected updated(changedProps: PropertyValues) {
@ -156,34 +158,48 @@ class PartialPanelResolver extends HassRouterPage {
}
}
private _handleVisibilityChange() {
private _checkVisibility() {
if (document.hidden) {
this._hiddenTimeout = window.setTimeout(() => {
this._hiddenTimeout = undefined;
const curPanel = this.hass.panels[this._currentPage];
if (
this.lastChild &&
// iFrames will lose their state when disconnected
// Do not disconnect any iframe panel
curPanel.component_name !== "iframe" &&
// Do not disconnect any custom panel that embeds into iframe (ie hassio)
(curPanel.component_name !== "custom" ||
!(curPanel.config as CustomPanelInfo).config._panel_custom
.embed_iframe)
) {
this._disconnectedPanel = this.lastChild;
this.removeChild(this.lastChild);
}
}, 300000);
this._onHidden();
} else {
if (this._hiddenTimeout) {
clearTimeout(this._hiddenTimeout);
this._hiddenTimeout = undefined;
this._onVisible();
}
}
private _onHidden() {
this._hiddenTimeout = window.setTimeout(() => {
this._hiddenTimeout = undefined;
// setTimeout can be delayed in the background and only fire
// when we switch to the tab or app again (Hey Android!)
if (!document.hidden) {
return;
}
if (this._disconnectedPanel) {
this.appendChild(this._disconnectedPanel);
this._disconnectedPanel = undefined;
const curPanel = this.hass.panels[this._currentPage];
if (
this.lastChild &&
// iFrames will lose their state when disconnected
// Do not disconnect any iframe panel
curPanel.component_name !== "iframe" &&
// Do not disconnect any custom panel that embeds into iframe (ie hassio)
(curPanel.component_name !== "custom" ||
!(curPanel.config as CustomPanelInfo).config._panel_custom
.embed_iframe)
) {
this._disconnectedPanel = this.lastChild;
this.removeChild(this.lastChild);
}
}, 300000);
window.addEventListener("focus", () => this._onVisible(), { once: true });
}
private _onVisible() {
if (this._hiddenTimeout) {
clearTimeout(this._hiddenTimeout);
this._hiddenTimeout = undefined;
}
if (this._disconnectedPanel) {
this.appendChild(this._disconnectedPanel);
this._disconnectedPanel = undefined;
}
}