Live location sharing - refresh beacon timers on tab becoming active (#8515)
* add visibilitychange listener Signed-off-by: Kerry Archibald <kerrya@element.io> * test Signed-off-by: Kerry Archibald <kerrya@element.io> * restore event listener mock Signed-off-by: Kerry Archibald <kerrya@element.io>pull/28788/head^2
parent
2c19d286ed
commit
e97536ef96
|
@ -15,8 +15,8 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { BeaconIdentifier, Room } from 'matrix-js-sdk/src/matrix';
|
import { Beacon, BeaconIdentifier, Room } from 'matrix-js-sdk/src/matrix';
|
||||||
|
|
||||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
@ -61,6 +61,25 @@ const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): strin
|
||||||
return _t('You are sharing your live location');
|
return _t('You are sharing your live location');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useLivenessMonitor = (liveBeaconIds: BeaconIdentifier[], beacons: Map<BeaconIdentifier, Beacon>): void => {
|
||||||
|
useEffect(() => {
|
||||||
|
// chromium sets the minimum timer interval to 1000ms
|
||||||
|
// for inactive tabs
|
||||||
|
// refresh beacon monitors when the tab becomes active again
|
||||||
|
const onPageVisibilityChanged = () => {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
liveBeaconIds.map(identifier => beacons.get(identifier)?.monitorLiveness());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (liveBeaconIds.length) {
|
||||||
|
document.addEventListener("visibilitychange", onPageVisibilityChanged);
|
||||||
|
}
|
||||||
|
() => {
|
||||||
|
document.removeEventListener("visibilitychange", onPageVisibilityChanged);
|
||||||
|
};
|
||||||
|
}, [liveBeaconIds, beacons]);
|
||||||
|
};
|
||||||
|
|
||||||
const LeftPanelLiveShareWarning: React.FC<Props> = ({ isMinimized }) => {
|
const LeftPanelLiveShareWarning: React.FC<Props> = ({ isMinimized }) => {
|
||||||
const isMonitoringLiveLocation = useEventEmitterState(
|
const isMonitoringLiveLocation = useEventEmitterState(
|
||||||
OwnBeaconStore.instance,
|
OwnBeaconStore.instance,
|
||||||
|
@ -91,6 +110,8 @@ const LeftPanelLiveShareWarning: React.FC<Props> = ({ isMinimized }) => {
|
||||||
const hasLocationPublishErrors = !!beaconIdsWithLocationPublishError.length;
|
const hasLocationPublishErrors = !!beaconIdsWithLocationPublishError.length;
|
||||||
const hasStoppingErrors = !!beaconIdsWithStoppingError.length;
|
const hasStoppingErrors = !!beaconIdsWithStoppingError.length;
|
||||||
|
|
||||||
|
useLivenessMonitor(liveBeaconIds, OwnBeaconStore.instance.beacons);
|
||||||
|
|
||||||
if (!isMonitoringLiveLocation) {
|
if (!isMonitoringLiveLocation) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ jest.mock('../../../../src/stores/OwnBeaconStore', () => {
|
||||||
public getBeaconById = jest.fn();
|
public getBeaconById = jest.fn();
|
||||||
public getLiveBeaconIds = jest.fn().mockReturnValue([]);
|
public getLiveBeaconIds = jest.fn().mockReturnValue([]);
|
||||||
public readonly beaconUpdateErrors = new Map<BeaconIdentifier, Error>();
|
public readonly beaconUpdateErrors = new Map<BeaconIdentifier, Error>();
|
||||||
|
public readonly beacons = new Map<BeaconIdentifier, Beacon>();
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -103,6 +104,10 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
||||||
mocked(OwnBeaconStore.instance).getLiveBeaconIds.mockReturnValue([beacon2.identifier, beacon1.identifier]);
|
mocked(OwnBeaconStore.instance).getLiveBeaconIds.mockReturnValue([beacon2.identifier, beacon1.identifier]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.spyOn(document, 'addEventListener').mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it('renders correctly when not minimized', () => {
|
it('renders correctly when not minimized', () => {
|
||||||
const component = getComponent();
|
const component = getComponent();
|
||||||
expect(component).toMatchSnapshot();
|
expect(component).toMatchSnapshot();
|
||||||
|
@ -195,6 +200,24 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
||||||
expect(component.html()).toBe(null);
|
expect(component.html()).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('refreshes beacon liveness monitors when pagevisibilty changes to visible', () => {
|
||||||
|
OwnBeaconStore.instance.beacons.set(beacon1.identifier, beacon1);
|
||||||
|
OwnBeaconStore.instance.beacons.set(beacon2.identifier, beacon2);
|
||||||
|
const beacon1MonitorSpy = jest.spyOn(beacon1, 'monitorLiveness');
|
||||||
|
const beacon2MonitorSpy = jest.spyOn(beacon1, 'monitorLiveness');
|
||||||
|
|
||||||
|
jest.spyOn(document, 'addEventListener').mockImplementation(
|
||||||
|
(_e, listener) => (listener as EventListener)(new Event('')),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(beacon1MonitorSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
getComponent();
|
||||||
|
|
||||||
|
expect(beacon1MonitorSpy).toHaveBeenCalled();
|
||||||
|
expect(beacon2MonitorSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
describe('stopping errors', () => {
|
describe('stopping errors', () => {
|
||||||
it('renders stopping error', () => {
|
it('renders stopping error', () => {
|
||||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error('error'));
|
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error('error'));
|
||||||
|
|
Loading…
Reference in New Issue